Broccoli's House

#7-(1) 학습 모델 구성 : 단순 모델 본문

공부/캡스톤 디자인

#7-(1) 학습 모델 구성 : 단순 모델

김콜리 2018. 4. 10. 00:39

7회차 - (1) 학습 모델 구성 : 단순 모델


  • 컬러 이미지


 - 앞서 흑백 이미지로 데이터를 모아서, 학습 모델을 구성하여 학습을 시켰다. 그러나 코스트(Cost) 즉, 오차 값이 굉장히 큰 값에서 수렴하여 줄어들지 않았다. 실제로는 모델 구성에 오류가 있었으나, 데이터가 워낙 많고 모델도 복잡하게 구성하다보니 오류를 찾기가 쉽지 않았다. 따라서 적은 데이터와 비교적 간단한 모델로 학습을 하여 어느 정도의 성능을 확인한 다음, 데이터를 많이 모으고 모델을 더 복잡하게 하기로 하였다.


 - 이미지의 수를 적게 하기로 했기 때문에, 흑백 보다는 컬러 이미지로 다시 데이터를 모았다. 컬러 이미지와 흑백 이미지의 가장 큰 차이는 이미지의 개수가 같다하여도 컬러 이미지는 RGB, 3채널이기 때문에 흑백 이미지보다 픽셀 수가 3배 더 많다는 것이다. 즉, 이미지의 개수는 같지만 데이터 자체는 3배 더 많은 것이다. 따라서 이미지의 수를 줄이는 대신 컬러 이미지로 학습을 하기로 한 것이다. 




  • 매개변수 선언 및 입력층 구성

 - 학습 모델 자체는 입력층, 은닉층, 출력층으로 구성되어 있고 이 세 층이 합쳐져 학습이 이루어진다. 입력층에서는 초매개변수(hyper-parameters)의 선언과 추후의 학습 시에 필요한 여러 작업들, 가장 주요하게는 입력 데이터를 받을 텐서(tensor)를 선언하는 것이 이루어진다.

# 이미지의 파일명이 모두 1부터 시작하는 정수여야 한다.

import tensorflow as tf
import os
import numpy as np
from PIL import Image
import random

text_path = '~/Training Data Color/' # 조향 데이터 경로
image_path = '~/Image Data/' # 이미지 경로

#----------------------------------------------------------------------------------------------------------------------

learning_rate = 0.001 # 학습율
total_epochs = 100 # 전체 에폭
tf.set_random_seed(777) # 텐서플로의 랜덤 시드 선언

#----------------------------------------------------------------------------------------------------------------------

img_list = os.listdir(image_path) # 이미지 경로가 있는 폴더에서 이미지 리스트를 받아온다.
total_data = len(img_list) # 전체 이미지 개수

Text_steering = open("%sSteering_Data.txt" % text_path, 'r') # 조향 데이터가 있는 텍스트 파일을 연다.
Steering_label = Text_steering.read().splitlines() # 텍스트 파일로부터 Tab을 기준으로 조향 데이터를 받아온다.

#----------------------------------------------------------------------------------------------------------------------

random.seed(444) # 랜덤 모듈의 시드 선언
random_indexes = random.sample(range(1, total_data+1), total_data)
# 데이터 전체를 섞기 위해 1부터 전체 데이터 개수까지 무작위로 된 정수 리스트를 만든다.

#----------------------------------------------------------------------------------------------------------------------

x = tf.placeholder(tf.float32, [70, 280, 3]) # (이미지 세로, 이미지 가로, 이미지 채널(컬러))에 대한 텐서 선언
x_st = tf.image.per_image_standardization(x) # 단일 이미지를 정규화하는 텐서 선언
x_img = tf.reshape(x_st, [1, 70, 280, 3]) # 정규화된 이미지 하나가 하나의 리스트 안에 들어가도록 변경
y_steering = tf.placeholder(tf.float32) # 조향 데이터 하나가 들어가는 텐서 선언




  • 은닉층 및 출력층 구성

 - 합성곱 신경망 3층, 완전 연결 신경망 2층의 은닉층과 출력층을 합하여 총 6층으로 이루어진 단순한 신경망 모델을 구성한다. 합성곱 신경망의 필터 사이즈는 모두 3X3, 스트라이드는 1로 설정하고, 모든 합성곱 층에서 이미지의 크기를 줄이는 풀링이 이루어지도록 하였다. 필터 사이즈와 개수, 스트라이드 및 완전 연결 신경망의 노드 개수는 관련 논문을 참조하여 설정하였다.


#-------------------------------------------------------------------------------------------------1st Convolution Layer

W1 = tf.Variable(tf.random_normal([3, 3, 3, 8], stddev=0.01)) # (3X3)사이즈의 필터 8개
L1 = tf.nn.conv2d(x_img, W1, strides=[1, 1, 1, 1], padding='SAME') # 합성곱 신경망 연산
L1 = tf.nn.relu(L1) # 렐루 활성화 함수
L1 = tf.nn.max_pool(L1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') # 이미지의 크기가 줄도록 풀링

#-------------------------------------------------------------------------------------------------2nd Convolution Layer

W2 = tf.Variable(tf.random_normal([3, 3, 8, 16], stddev=0.01))
L2 = tf.nn.conv2d(L1, W2, strides=[1, 1, 1, 1], padding='SAME')
L2 = tf.nn.relu(L2)
L2 = tf.nn.max_pool(L2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

#-------------------------------------------------------------------------------------------------3rd Convolution Layer

W3 = tf.Variable(tf.random_normal([3, 3, 16, 32], stddev=0.01))
L3 = tf.nn.conv2d(L2, W3, strides=[1, 1, 1, 1], padding='SAME')
L3 = tf.nn.relu(L3)
L3 = tf.nn.max_pool(L3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
L3_flat = tf.reshape(L3, [-1, 9 * 35 * 32]) # 완전 연결 신경망에 넣어주기 위해 이미지를 평탄화 해준다.

#---------------------------------------------------------------------------------------------4th Fully Connected Layer

W4 = tf.get_variable('W4', shape=[32 * 35 * 9, 128], initializer=tf.contrib.layers.xavier_initializer())
b4 = tf.Variable(tf.random_normal([128]))
L4 = tf.nn.relu(tf.matmul(L3_flat, W4) + b4)

#---------------------------------------------------------------------------------------------5th Fully Connected Layer

W5 = tf.get_variable('W5', shape=[128, 64], initializer=tf.contrib.layers.xavier_initializer())
b5 = tf.Variable(tf.random_normal([64]))
L5 = tf.nn.relu(tf.matmul(L4, W5) + b5)

#----------------------------------------------------------------------------------------------------------Output Layer

W6 = tf.get_variable('W6', shape=[64, 1], initializer=tf.contrib.layers.xavier_initializer())
b6= tf.Variable(tf.random_normal([1]))
hypothesis = tf.matmul(L5, W6) + b6 




  • 학습
 - 최소 제곱법으로 손실 함수를 정의하고, 손실 함수를 최소화하는 최적화 기법으로는 Adam을 사용한다. 앞서 입력층에서 선언했던 입력 텐서 x, y에 이미지와 조향 데이터를 넣고 학습을 수행한다.

#-----------------------------------------------------------------------------------------------Define cost & optimizer

cost = tf.reduce_mean(tf.square(hypothesis - y_steering)) # 손실 함수 계산
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost) # 손실 함수 최소화

sess = tf.Session() # 텐서플로 구동
sess.run(tf.global_variables_initializer()) # 변수 초기화

#--------------------------------------------------------------------------------------------------------------Learning

print('Learning started. It takes sometime...')

for epoch in range(total_epochs) :

avg_cost = 0

for index in range(total_data) :

training_img = np.array(Image.open('%s%s.PNG' % (image_path, random_indexes[index]))) # 단일 이미지 배열
training_label = float(Steering_label[random_indexes[index] - 1]) # 조향 데이터

feed_dict = {x: training_img, y_steering: training_label}
c, h, _ = sess.run([cost, hypothesis, optimizer], feed_dict=feed_dict) # 학습
avg_cost += c

print('Epoch : ' + '%d ' % (epoch + 1), 'cost = ', '{:.5f}'.format(avg_cost/total_data))

print('Learning Finished!')


 - 대략 만 개의 데이터로 학습을 하면, 처음에 1에폭 때의 손실 함수 값은 75정도에서 시작하여 10에폭이 지나면 6까지 떨어진다. 에폭이 50 이상으로 학습을 하면 0.3~0.4 정도의 값에 손실 함수가 수렴하게 된다.




  • 전체 코드


# 이미지의 파일명이 모두 1부터 시작하는 정수여야 한다.

import tensorflow as tf
import os
import numpy as np
from PIL import Image
import random

text_path = '~/Training Data Color/'
image_path = '~/Training Data Color/Image Data/'

#----------------------------------------------------------------------------------------------------------------------

learning_rate = 0.001 # 학습율
total_epochs = 10 # 전체 에폭
tf.set_random_seed(777) # 텐서플로의 랜덤 시드 선언

#----------------------------------------------------------------------------------------------------------------------

img_list = os.listdir(image_path) # 이미지 경로가 있는 폴더에서 이미지 리스트를 받아온다.
total_data = len(img_list) # 전체 이미지 개수

Text_steering = open("%sSteering_Data.txt" % text_path, 'r') # 조향 데이터가 있는 텍스트 파일을 연다.
Steering_label = Text_steering.read().splitlines() # 텍스트 파일로부터 Tab을 기준으로 조향 데이터를 받아온다.

#----------------------------------------------------------------------------------------------------------------------

random.seed(444) # 랜덤 모듈의 시드 선언
random_indexes = random.sample(range(1, total_data+1), total_data)
# 데이터 전체를 섞기 위해 1부터 전체 데이터 개수까지 무작위로 된 정수 리스트를 만든다.

#----------------------------------------------------------------------------------------------------------------------

x = tf.placeholder(tf.float32, [70, 280, 3]) # (이미지 세로, 이미지 가로, 이미지 채널(컬러))에 대한 텐서 선언
x_st = tf.image.per_image_standardization(x) # 단일 이미지를 정규화하는 텐서 선언
x_img = tf.reshape(x_st, [1, 70, 280, 3]) # 정규화된 이미지 하나가 하나의 리스트 안에 들어가도록 변경
y_steering = tf.placeholder(tf.float32) # 조향 데이터 하나가 들어가는 텐서 선언
#
#-------------------------------------------------------------------------------------------------1st Convolution Layer
#
W1 = tf.Variable(tf.random_normal([3, 3, 3, 8], stddev=0.01)) # (3X3)사이즈의 필터 8개
L1 = tf.nn.conv2d(x_img, W1, strides=[1, 1, 1, 1], padding='SAME') # 합성곱 신경망 연산
L1 = tf.nn.relu(L1) # 렐루 활성화 함수
L1 = tf.nn.max_pool(L1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') # 이미지의 크기가 줄도록 풀링

#-------------------------------------------------------------------------------------------------2nd Convolution Layer

W2 = tf.Variable(tf.random_normal([3, 3, 8, 16], stddev=0.01))
L2 = tf.nn.conv2d(L1, W2, strides=[1, 1, 1, 1], padding='SAME')
L2 = tf.nn.relu(L2)
L2 = tf.nn.max_pool(L2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

#-------------------------------------------------------------------------------------------------3rd Convolution Layer

W3 = tf.Variable(tf.random_normal([3, 3, 16, 32], stddev=0.01))
L3 = tf.nn.conv2d(L2, W3, strides=[1, 1, 1, 1], padding='SAME')
L3 = tf.nn.relu(L3)
L3 = tf.nn.max_pool(L3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
L3_flat = tf.reshape(L3, [-1, 9 * 35 * 32]) # 완전 연결 신경망에 넣어주기 위해 이미지를 평탄화 해준다.

#---------------------------------------------------------------------------------------------4th Fully Connected Layer

W4 = tf.get_variable('W4', shape=[32 * 35 * 9, 128], initializer=tf.contrib.layers.xavier_initializer())
b4 = tf.Variable(tf.random_normal([128]))
L4 = tf.nn.relu(tf.matmul(L3_flat, W4) + b4)

#---------------------------------------------------------------------------------------------5th Fully Connected Layer

W5 = tf.get_variable('W5', shape=[128, 64], initializer=tf.contrib.layers.xavier_initializer())
b5 = tf.Variable(tf.random_normal([64]))
L5 = tf.nn.relu(tf.matmul(L4, W5) + b5)

#----------------------------------------------------------------------------------------------------------Output Layer

W6 = tf.get_variable('W6', shape=[64, 1], initializer=tf.contrib.layers.xavier_initializer())
b6= tf.Variable(tf.random_normal([1]))
hypothesis = tf.matmul(L5, W6) + b6
#
#-----------------------------------------------------------------------------------------------Define cost & optimizer

cost = tf.reduce_mean(tf.square(hypothesis - y_steering)) # 손실 함수 계산
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost) # 손실 함수 최소화

sess = tf.Session() # 텐서플로 구동
sess.run(tf.global_variables_initializer()) # 변수 초기화

#--------------------------------------------------------------------------------------------------------------Learning

print('Learning started. It takes sometime...')

for epoch in range(total_epochs) :

avg_cost = 0

for index in range(total_data) :

training_img = np.array(Image.open('%s%s.PNG' % (image_path, random_indexes[index]))) # 단일 이미지 배열
training_label = float(Steering_label[random_indexes[index] - 1]) # 조향 데이터

feed_dict = {x: training_img, y_steering: training_label}
c, h, _ = sess.run([cost, hypothesis, optimizer], feed_dict=feed_dict) # 학습
avg_cost += c

print('Epoch : ' + '%d ' % (epoch + 1), 'cost = ', '{:.5f}'.format(avg_cost/total_data))

print('Learning Finished!')


Comments