Broccoli's House

#7-(2) 학습 모델 구성 : 배치 모델 본문

공부/캡스톤 디자인

#7-(2) 학습 모델 구성 : 배치 모델

김콜리 2018. 4. 10. 22:45

7회차 - (2) 학습 모델 구성 : 배치 처리 모델


  • 배치 처리

 - 3천개 가량의 컬러 이미지로 모델 성능을 확인하기 위하여 단일 이미지 - 단일 라벨 방식으로 학습을 진행하였다. 컬러 이미지를 1만개 정도로 더 모아서 학습을 진행하려 하는데, 단일 데이터 학습 방식은 효과적이지 못하여 배치 단위로 학습을 하고자 한다. 단일 모델과 전체적인 구조에서 큰 차이는 없으나, 배치 처리 모델은 입력 데이터를 받을 텐서와 단일 이미지 정규화, 배치 정규화같은 부분에서 단일 모델과 차이가 있다.




  • 입력 데이터 배치 처리

 - 라벨인 조향 각도의 경우 텍스트 파일에 저장되어 있어서, 전체 조향 데이터를 파이썬에서 리스트의 형태로 불러다 배치 크기만큼 자르면 되서 그리 어렵지 않게 구현할 수 있다. 이미지의 경우에는 전체를 불러오면 메모리 용량을 넘거나 너무 많이 차지해서 학습 속도에 영향을 끼칠 수 있으므로 라벨과 같은 방식으로 배치 처리를 할 수 없다. 따라서 이미지를 하나씩 불러다 비어있는 리스트에 넣는 방식으로 배치 처리를 구현한다. 또한 입력 데이터를 불러오는 코드가 지저분하므로 다른 파이썬 파일에서 함수로 선언하여 학습 모델 파일에서 모듈로 불러오도록 한다.


import tensorflow as tf
import numpy as np
import random
import os
from PIL import Image
from astropy.visualization import MinMaxInterval
interval = MinMaxInterval()

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

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()

random.seed(444)
random_indexes = random.sample(range(1, total_data + 1), total_data)


def get_img_list() :

img_list = os.listdir(image_path)

return img_list


def read_batch(batch_index, batch_size) :

training_img = []
training_label = []

batch_count = batch_index * batch_size

for random_index in random_indexes[batch_count : (batch_count + batch_size)] :

training_img.append(interval(np.array(Image.open('%s%s.PNG' % (image_path, str(random_index))))))
training_label.append([float(Steering_label[random_index - 1])])

return training_img, training_label


 - 단일 모델에서는 텐서플로의 tf.image.per_image_standardization() 함수를 통해 이미지를 정규화하였지만, 배치 처리를 하면 텐서로 정규화하지 못하고 배치 처리하기 전에 이미지를 정규화 해주어야한다. astropy의 visualization 모듈에서 MinMaxScaler() 함수를 사용하여 단일 이미지를 정규화(Normalization)한 다음, 배치 리스트에 추가하는 방식을 사용한다.




  • 배치 정규화

 - 단일 이미지를 정규화하는 방식말고도, 배치 처리를 할 때는 배치 정규화(batch-normalization)를 사용할 수 있다. 배치 정규화를 사용하면 학습 성능이 향상되고, 초매개변수의 영향을 덜 받으며, 드롭아웃을 사용할 필요가 없어 학습 속도도 향상된다. 배치 정규화 또한 텐서플로에 이미 있는 함수를 사용하는데, 그러기 위해서는 입력 텐서의 평균과 분산을 구해야 한다. 따라서 매번 배치가 달라질 때마다 평균과 분산을 구해주어야 하므로 입력 데이터를 배치 처리한 것과 마찬가지로 다른 파이썬 파일에서 함수로 선언하여 불러쓰도록 한다.


def batch_norm_cnn(batch_image, depth) :

epsilon = 1e-5
beta = tf.Variable(tf.constant(0.0, shape=[depth]), trainable=True)
gamma = tf.Variable(tf.constant(1.0, shape=[depth]), trainable=True)
mean, variance = tf.nn.moments(batch_image, axes=[0, 1, 2])

norm_batch = tf.nn.batch_normalization(batch_image, mean, variance, beta, gamma, epsilon)

return norm_batch


def batch_norm_flat(batch_flat) :

epsilon = 1e-5
beta = tf.Variable(tf.constant(0.0, shape=[1]), trainable=True)
gamma = tf.Variable(tf.constant(1.0, shape=[1]), trainable=True)
mean, variance = tf.nn.moments(batch_flat, axes=[0])

norm_batch = tf.nn.batch_normalization(batch_flat, mean, variance, beta, gamma, epsilon)

return norm_batch


 - 합성곱 신경망과 완전 연결 신경망에서의 배치 정규화 함수를 다르게 만들어준다. 입력되는 데이터의 차원이 다르기 때문에 배치의 평균과 분산을 구하기 위해 tf.nn.moments() 함수를 사용함에 있어 축(axes)을 달리 선언해주는 것과, 데이터의 깊이(depth), 즉 이미지의 채널 혹은 필터 개수를 합성곱 신경망의 배치 정규화에서 사용한다는 점이 둘의 차이점이다.




  • 전체 코드

 - 전체 코드는 앞서의 단일 모델과 크게 다르지 않다. 다만 입력층에서 입력 데이터를 받는 텐서의 크기나, 배치 정규화를 사용하면서 필요없어지는 편향(bias), 드롭아웃(drop-out)과 같은 항목이 사라지는 등의 변화만이 있을 뿐이다. 전체적인 구성과 층의 개수 등은 동일하다.


import tensorflow as tf
import func_Training as ftr

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

img_height = 70
img_width = 280
img_channel = 3

learning_rate = 0.001
total_epochs = 100
tf.set_random_seed(777)

batch_size = 100

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

img_list = ftr.get_img_list()
total_data = len(img_list)
total_batch = int(total_data / batch_size)

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

x = tf.placeholder(tf.float32, [None, img_height, img_width, img_channel])
x_img = tf.reshape(x, [-1, img_height, img_width, img_channel])
y_steering = tf.placeholder(tf.float32, [None, 1])

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

W1 = tf.Variable(tf.random_normal([3, 3, 3, 8], stddev=0.01))
L1 = tf.nn.conv2d(x_img, W1, strides=[1, 1, 1, 1], padding='SAME')
L1 = ftr.batch_norm_cnn(L1, 8)
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 = ftr.batch_norm_cnn(L2, 16)
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 = ftr.batch_norm_cnn(L3, 32)
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())
L4 = tf.matmul(L3_flat, W4)
L4 = ftr.batch_norm_flat(L4)
L4 = tf.nn.relu(L4)

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

W5 = tf.get_variable('W5', shape=[128, 64], initializer=tf.contrib.layers.xavier_initializer())
L5 = tf.matmul(L4, W5)
L5 = ftr.batch_norm_flat(L5)
L5 = tf.nn.relu(L5)

#----------------------------------------------------------------------------------------------------------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())
saver = tf.train.Saver()

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

print('\n' + 'Learning started...' + '\n')

for epoch in range(total_epochs) :

avg_cost = 0

for batch_index in range(total_batch):

training_img, training_label = ftr.read_batch(batch_index, batch_size)
feed_dict = {x: training_img, y_steering: training_label}
c, h, _ = sess.run([cost, hypothesis, optimizer], feed_dict=feed_dict)
avg_cost += c

if (batch_index + 1) % 5 == 0 :

print('batch : %d ' % (batch_index + 1), 'cost = {:.4f} '.format(avg_cost / ((batch_index + 1) * batch_size)))

saver.save(sess, "~/my_train_model")
print('\n' + 'Epoch : ' + '%d ' % (epoch + 1), 'cost = ', '{:.4f}'.format(avg_cost/total_data) + '\n')

print('Learning Finished!') 




  • 학습 결과



Comments