2020. 2. 12. 19:03 ㆍ개발 이야기/머신러닝(딥러닝)
안녕하세요
오늘은 인공신경망의 동작 원리 중 MLP에 대해서 알아보도록 하겠습니다. 참고한 블로그는 아래와 같습니다.
Multilayer Perceptron(MLP) Tutorial
(흰고래의 꿈 블로그)
먼저 MLP는 뭘까요? Multilayer Perceptron으로 다층 퍼셉트론을 의미하고 있습니다. 그러면 퍼셉트론은 뭘까요?
지난번 블로그에서 뉴런에 대해서 다뤘었는데요 이 뉴런을 딥러닝에서 구현한 것을 퍼셉트론이라고 합니다. 여러개의 층으로 구현된 뉴런이 바로 MLP가 되겠죠?
이 MLP를 어떻게 구현하고 어떻게 학습시키는지 테스트 코드를 디버깅하면서 알아보도록 하겠습니다.
먼저 테스트 데이터는 위에서 소개한 흰고래의 꿈님의 블로그에서 가져왔는데요 테스트 데이터를 보면
순서대로 쭉 나열된 데이터를 볼 수 있습니다. 왼쪽의 sequential하게 나열된 데이터와 그에 맞는 값이 있는데요 순서에 따라 값이 증감하는 것을 볼 수 있습니다. 자 그럼 디버깅을 하면서 하나씩 확인해보도록 하겠습니다. 먼저 hidden_node_num 리스트는 층 별 노드의 갯수, hidden_layer_num는 층 수 입니다. 텍스트 데이터를 import 해서 텍스트 데이터를 numpy로 generate 해줍니다
NumPy는 행렬이나 일반적으로 대규모 다차원 배열을 쉽게 처리 할 수 있도록 지원하는 파이썬의 라이브러리이다. NumPy는 데이터 구조 외에도 수치 계산을 위해 효율적으로 구현된 기능을 제공한다.
hidden_node_num = [10, 9, 8] # 층별 노드의 갯수
hidden_layer_num = len(hidden_node_num) # 히든 레이어 층 수
# load data
data_file_name = 'x_square.txt'
xy = np.genfromtxt(data_file_name, dtype='float32') # txt 파일 generate
temp_x = xy[:, 0] # file 내에 0열 값을 temp_x에 저장
temp_y = xy[:, 1] # file 내에 1열 값을 temp_y에 저장
x_data = [temp_x]
y_data = [temp_y] # ndarray를 List 형태로 변환
x = tf.placeholder(dtype=tf.float32) # tensor placeholder 생성 (값 저장소), 매개변수
y = tf.placeholder(dtype=tf.float32)
파일의 0번째 열 값들을 temp_x에 1번째 열 값들을 temp_y에 저장해주고 list 형태로 변환해줍니다. 직접 디버깅해보겠습니다.
x_data에 list 형태로 값이 담겨있는 것을 볼 수 있습니다. 테스트 데이터의 0번째 열데이터를 가져온 것이죠?
y_data에는 1열 값들이 전부 순서대로 담겨있는 것을 볼 수 있습니다. 그리고 여기서 중요한 것은 placeholder 개념이 등장합니다. 어려운 개념은 아니지만 머신러닝을 접해본 사람이 아니라면 익숙하지 않은 부분입니다.
이 placeholder는 tensor를 담을 수 있는 변수인데요!
tensor란? 벡터의 확장 개념. 수학 · 물리학에서 중요한 역할을 하는 텐서는 벡터의 개념을 포함한다.
사용을 위해서는 먼저 만들어주어야합니다. 그리고는
w = [] # 가중치 list
b = [] # 편향 List
layer = [] # model list
x_data_len = len(x_data)
노드로 사용할 list를 만들어줍니다. 하위 부분 부터는 이해를 위해 그림과 함께하도록 하겠습니다.
# first layer
w.append(tf.Variable(tf.random_normal([hidden_node_num[0], x_data_len]), name="w0")) # 10, 1 인 2차원 텐서 생성
b.append(tf.Variable(tf.random_normal([hidden_node_num[0], 1]), name="b0"))
name = w0을 갖는 tensor를 추가해줍니다.
여기서 몇 가지 알아야할 텐서플로우 메서드가 있는데요 Variable 함수는 텐서에 값을 정의해주는 함수이고 random_normal 함수는 정규분포의 무작위 값으로 초기화 해주는 함수입니다!
hidden_node_num[0]에는 10이 들어있고 x_data_len은 1이기 때문에 w, b 모두 10, 1 모양의 텐서가 추가된 것을 알 수 있습니다.
W는 가중치(weight), B는 편향(bias)를 의미하는데요
입력값 X에 가중치(W)를 곱하고 편향(B)를 더한 뒤 활성화 함수(Sigmoid, ReLU 등)을 거쳐
결괏값 Y를 만들어 내는것이 인공 뉴런, 퍼셉트론의 기본입니다.
원하는 Y 값을 찾아 내기위해 W, B의 값을 변경해 가면서 적절한 값을 찾아내는 최적화 과정을 학습(Learning) 또는 훈련(training) 이라고 합니다.
먼저 w, b에 append된 것을 그려보면 아래와 같습니다.
Hidden layer의 추가 부분을 보겠습니다.
# add hidden layers (variable number)
for i in range(1, hidden_layer_num):
wName = "w" + str(i)
bName = "b" + str(i)
w.append(tf.Variable(tf.random_normal([hidden_node_num[i], hidden_node_num[i - 1]]), name=wName))
b.append(tf.Variable(tf.random_normal([hidden_node_num[i], 1]), name=bName))
for 문을 따라 w1, w2, w3 히든 레이어가 추가 되는 것을 확인할 수 있습니다.
중요한 것은 w의 히든레이어 노드 갯수가 10, 9, 8 순서로 하나씩 줄여가면서 append 되는것을 볼수 있습니다.
히든레이어까지 append된 모양을 보면 아래와 같습니다.
자 이제 마지막 Layer를 추가하겠습니다.
# add final layer
wName = "w" + str(hidden_layer_num)
bName = "b" + str(hidden_layer_num)
w.append(tf.Variable(tf.random_normal([1, hidden_node_num[-1]]), name=wName))
b.append(tf.Variable(tf.random_normal([1], 1), name=bName))
마지막 Output Layer는 1로 노드는 아래와 같게 됩니다.
자 이제 모델을 정의하겠습니다. 먼저 사용하는 활성화 함수는 Sigmoid를 사용했습니다. 위에서 설명했듯 가중치(w)와 입력값(x)의 곱 + 평향으로 layer를 정의해줍니다. 첫 줄은 첫번째 입력층이고, for문 안에 있는 것은 은닉층을 append 해줍니다.
# define model
layer.append(tf.nn.sigmoid(tf.matmul(w[0], x) + b[0]))
for i in range(1, hidden_layer_num):
layer.append(tf.nn.sigmoid(tf.matmul(w[i], layer[i - 1]) + b[i]))
y_out = tf.matmul(w[-1], layer[-1]) + b[-1]
경사하강법(GradientDescent)보다 좋은 효과를 나타낸다는 Adam을 이용해 Optimizing을 해줍니다
cost = tf.nn.l2_loss(y_out - y)
opt = tf.train.AdamOptimizer(0.1) # GradientDescent 보다 성능이 좋은 옵티마이저
모델을 트레이닝하고 테스트 데이터를 만들어 그래프로 그려줍니다.
with tf.Session() as sess:
sess.run(init)
for i in range(5000):
sess.run(train, feed_dict={x: x_data, y: y_data})
# generate test data
x_temp = np.linspace(0, 20, 50)
x_test = [x_temp]
y_test = sess.run(y_out, feed_dict={x: x_test})
np.linspace 함수를 이용해 50개의 테스트 데이터를 추출합니다.
y = linspace(x1,x2)는 x1과 x2 사이에서 균일한 간격의 점 100개로 구성된 행 벡터를 반환합니다.
y = linspace(x1,x2,n)은 n개의 점을 생성합니다. 점 사이의 간격은 (x2-x1)/(n-1)입니다.
linspace는 콜론 연산자 “:”과 유사하지만, 점 개수를 직접 제어할 수 있으며 항상 끝점을 포함합니다.
이름 “linspace”의 “lin”은 선형 간격 값을 생성하는 것을 나타내며,
#는 로그 간격 값을 생성하는 형제 함수 logspace와 대조됩니다.
matplotlib 모듈을 이용해 그래프로 표현해줍니다.
# design graph
plt.plot(x_data, y_data, 'ro', alpha=0.05)
plt.plot(x_test, y_test, 'h', alpha=1)
plt.show()
여기서 "ro"와 "h" 값이 궁금한 사람들을 위해 plot 사용방법을 첨부합니다.
실행하게되면 다음과 같은 결과물이 출력됩니다.
빨간색 선은 러닝된 모델이고 테스트 데이터를 input 했을때 나온 output이 알록달록한 동그라미 입니다.
소스코드는 다음과 같습니다.
# coding=utf-8
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
hidden_node_num = [10, 9, 8, 7]
hidden_layer_num = len(hidden_node_num)
# load data
data_file_name = 'x_square.txt'
xy = np.genfromtxt(data_file_name, dtype='float32')
temp_x = xy[:, 0]
temp_y = xy[:, 1]
x_data = [temp_x]
y_data = [temp_y] # ndarray를 List 형태로 변환
x = tf.placeholder(dtype=tf.float32) # tensor placeholder 생성 (값 저장소), 매개변수
y = tf.placeholder(dtype=tf.float32)
w = []
b = []
layer = []
x_data_len = len(x_data)
# first layer
w.append(tf.Variable(tf.random_normal([hidden_node_num[0], x_data_len]), name="w0")) # 10, 1 인 2차원 텐서 생성
b.append(tf.Variable(tf.random_normal([hidden_node_num[0], 1]), name="b0"))
# add hidden layers (variable number)
for i in range(1, hidden_layer_num):
wName = "w" + str(i)
bName = "b" + str(i)
w.append(tf.Variable(tf.random_normal([hidden_node_num[i], hidden_node_num[i - 1]]), name=wName))
b.append(tf.Variable(tf.random_normal([hidden_node_num[i], 1]), name=bName))
# add final layer
wName = "w" + str(hidden_layer_num)
bName = "b" + str(hidden_layer_num)
w.append(tf.Variable(tf.random_normal([1, hidden_node_num[-1]]), name=wName))
b.append(tf.Variable(tf.random_normal([1], 1), name=bName))
# define model
layer.append(tf.nn.sigmoid(tf.matmul(w[0], x) + b[0]))
for i in range(1, hidden_layer_num):
layer.append(tf.nn.sigmoid(tf.matmul(w[i], layer[i - 1]) + b[i]))
y_out = tf.matmul(w[-1], layer[-1]) + b[-1]
# setup cost function and optimizer
# cost = tf.reduce_mean(tf.square(y_out - y))
# opt = tf.train.GradientDescentOptimizer(learning_rate=0.01)
cost = tf.nn.l2_loss(y_out - y)
opt = tf.train.AdamOptimizer(0.1) # GradientDescent 보다 성능이 좋은 옵티마이저
train = opt.minimize(cost)
# training model
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
for i in range(5000):
sess.run(train, feed_dict={x: x_data, y: y_data})
# generate test data
x_temp = np.linspace(0, 20, 50)
x_test = [x_temp]
y_test = sess.run(y_out, feed_dict={x: x_test})
print(len(x_temp))
print(x_test)
print(y_test)
# design graph
plt.plot(x_data, y_data, 'ro', alpha=0.05)
plt.plot(x_test, y_test, 'h', alpha=1)
plt.show()
이상으로 tensorflow를 이용한 MLP 구현예제를 디버깅해봤습니다.
'개발 이야기 > 머신러닝(딥러닝)' 카테고리의 다른 글
# [Lazy Predict] 분류, 회귀분석 간소화 프로젝트 (0) | 2021.07.13 |
---|---|
# 데이터 분석&머신러닝 플랫폼 - RapidMiner(래피드마이너) (0) | 2020.04.22 |
#2 인공신경망 동작 원리 - 뉴런 (0) | 2020.02.06 |
#1 인공신경망 동작 원리 - 예측자, 분류자 (0) | 2020.02.05 |
#6 음성인식 노이즈 제거2 (0) | 2019.10.11 |