분류 전체보기 (339)

반응형

/**

2017.02.02 작성자 : 3개월

Tensorflow - MNIST 단일 계층 신경망 트레이닝

*/


환경 : windows tensorflow, anaconda 4.3, python 3.5



Tensorflow를 통해 단일 계층 신경망을 구축하고 MNIST 데이터를 training하고 test 하는 예제입니다. 많은 예제들이 tensorflow 내부에 example로 있는 MNIST 데이터를 이용하지만 이 포스팅에서는 외부에 있는 MNIST pickle 파일을 다운로드하고 이를 읽어들여 모델을 구축해보았습니다. 사용한 MNIST pickle 파일은 https:na//github.com/mnielsen/neural-networks-and-deep-learning/blob/master/data/mnist.pkl.gz 이곳에서 다운로드 받을 수 있습니다. 


1. 데이터 읽기


import tensorflow as tf
import gzip, numpy
import pickle as cPickle
import pandas as pd

# Load the dataset
f = open('data/mnist.pkl', 'rb')
train_set, valid_set, test_set = cPickle.load(f, encoding='latin1')
f.close()

x_train, y_train = train_set
x_test, y_test = test_set


pickle로 불러온 변수에는 train_set, valid_set, test_set이 나뉘어져 있기 때문에 위와 같이 load하면 알아서 training, validation, test set으로 나눌 수 있습니다. 또한 각각은 튜플 자료구조형으로 또 다시 x, y로 나뉘어져 있기 때문에 x_train, y_train = train_set 구문을 통해 feature과 label을 분리할 수 있습니다. 이렇게 데이터를 빠르게 training을 적용할 수 있는 형태로 만들어낼 수 있다는 것이 pickle 파일의 좋은 점입니다. 하지만 예제가 아닌 실제 머신러닝 모델을 구축할 때는 이러한 과정을 모두 직접하여야 합니다. 이미지 파일을 읽어들여야하고 또 이것을 적절한 사이즈의 numpy array로 바꾸어야합니다. 


2. 데이터 전처리


y_train = pd.get_dummies(y_train)
y_test = pd.get_dummies(y_test)


label들을 one hot encoding합니다. tensorflow에서는 label을 one hot encoding 하여 제공하여야 합니다.


print('x_train shape : ',x_train.shape) # (50000, 784)
print('y_train shape : ',y_train.shape) # (50000, 10)
print('x_test shape : ',x_test.shape) # (10000, 784)
print('y_test shape : ',y_test.shape) # (10000, 10)


training data와 test data의 형태(shape)를 프린트하여 보겠습니다. MNIST 데이터는 28*28 흑백 이미지이므로 총 784개의 픽셀이 있는데 이를 feature로 보아 784개의 feature가 있음을 알 수 있습니다. 


[mnist 데이터 모양]



또한 training data의 갯수는 50000개이기 때문에 x_train의 모양은 50000*784 입니다. label의 갯수도 50000개이며 class의 갯수가 0~9까지 10개이므로 y_train은 50000*10입니다. 만약 label이 1인 경우 y는 [0 1 0 0 0 0 0 0 0 0 0] 으로 encoding 됩니다. y_train에는 이러한 y가 50000개 있다고 생각하면 됩니다.


3. 모델 작성


x = tf.placeholder('float', [None, 784]) W = tf.Variable(tf.zeros([784,10])) b = tf.Variable(tf.zeros([10])) y = tf.nn.softmax(tf.matmul(x, W) + b) y_ = tf.placeholder('float', [None, 10]) cross_entropy = -tf.reduce_sum(y_*tf.log(y)) train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)


윗 부분은 데이터를 읽어들이고 numpy와 pandas를 이용하여 데이터를 전처리 한 것이었다면 이제부터는 본격적으로 tensorflow 코드를 작성하여 보겠습니다.


x = tf.placeholder('float', [None, 784])


우선 placeholder을 이용해 x가 들어갈 공간을 만들어줍니다. 이 때 [None, 784]에서 None은 데이터의 갯수는 자유롭게 설정하겠다는 뜻입니다. 하지만 feature의 갯수 784는 고정되어 있습니다. 


W = tf.Variable(tf.zeros([784,10]))


그 다음 weight matrix를 만드는데 input layer의 노드가 784개이고 output layer의 노드가 10개이므로 총 784*10개의 weights가 필요한 것을 알 수 있습니다. 이를 위해 W라는 tensorflow 변수를 만들고 0으로 초기화 시킵니다. 


b = tf.Variable(tf.zeros([10]))


bias는 output layer의 node수만큼 필요하므로 10개를 만들고 0으로 초기화 시킵니다.


y = tf.nn.softmax(tf.matmul(x, W) + b)


그 다음 x와 W를 매트릭스 곱셈을 하고 bias를 더한 것에 softmax 함수를 취하여 이를 y 변수로 만들어줍니다. 수식으로 표현하면  y = softmax(xW+b) 이 됩니다. 이 때 y는 '예측값' 입니다.


cross_entropy = -tf.reduce_sum(y_*tf.log(y)) train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)


손실 함수로는 classification의 경우 크로스 엔트로피를 사용하게 됩니다. -y_*log(y) 에는 데이터들의 크로스 엔트로피들의 2차원 텐서가 담겨져 있습니다. reduce_sum 함수를 통해 이 크로스 엔트로피들의 평균을 구합니다. 이 때 reduce_sum 함수는 지정된 차원을 따라 평균을 내는 것입니다. 2차원인 경우 지정할 차원이 1개 밖에 없으므로 차원을 따로 지정한 필요가 없습니다. 그래서 이 경우에는 reduce_sum 함수는 평균을 구한다고 생각하시면 됩니다.



4. 배치 트레이닝


sess = tf.Session()
sess.run(tf.global_variables_initializer())

batch_size = 100 # 배치 사이즈 지정
training_epochs = 3 # epoch 횟수 지정

# epoch 횟수만큼 반복
for epoch in range(training_epochs) :
    batch_count = int(x_train.shape[0]/100) # 배치의 갯수
    for i in range(batch_count) : # 배치를 순차적으로 읽는 루프
        # 배치사이즈 만큼 데이터를 읽어옴
        batch_xs, batch_ys = x_train[i*batch_size:i*batch_size+batch_size], y_train[i*batch_size:i*batch_size+batch_size] 
        
        # training, 이를 통해 W, b Variable 값을 조정함
        sess.run(train_step, feed_dict = {x : batch_xs, y_ : batch_ys})
        
        # [True False True False False True True ....] 와 같은 boolean vector
        correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
        
        # [1 0 1 0 0 1 1 ...]로 변환 후 평균값을 구하면 accuracy 구할 수 있음
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
        
        # 5번 배치를 읽고 이를 트레이닝한 후 정확도 출력
        if i % 5 == 0 : 
            print(str(epoch+1)+' epoch '+ str(i)+' batch ', sess.run(accuracy, feed_dict={x: x_test[0:100], y_: y_test[0:100]}))


이 부분을 이해하기 위해서는 우선 배치 트레이닝에 대하여 알아야 합니다. 배치 트레이닝이란 트레이닝 데이터를 일정 사이즈로 쪼갠 미니 배치(mini batch)를 통해 Gradient Descent를 하는 방법입니다. 일반적인 Gradient Descent 방법은 전체 트레이닝 데이터를 한 번 쭉 보고 gradient를 구한 후 weights와 bias를 '한 번' 업데이트 시킵니다. 하지만 이런 방법은 computation cost가 높습니다. 하지만 미니 배치를 이용한 방법은 전체 데이터의 샘플인 미니 배치를 통해 전체 데이터를 근사 시킵니다. 그리고 이것만 보고 gradient를 구한 후 weight, bias를 업데이트 시킵니다. 예를 들어 배치 사이즈가 128이면 128개의 데이터 샘플들만 보고 gradient를 구한 후 weight, bias를 업데이트 하게 됩니다. 이전 방식에 비해 훨씬 빠르게 weight를 업데이트 시킬 수 있죠. 이렇게 weight를 구하는 방식은 Stochastic Gradient Descent 방법이라고 부릅니다. 실제로 일반적인 Gradient Descent 방법보다는 Stochastic Gradient Descent 방법이 더 많이 쓰입니다. 팁으로는 배치 사이즈는 메모리가 허용하는 범위 내에서 최대한 크게 잡는 것이 좋습니다. 그리고 보통 배치사이즈는 128, 256, 512와 같이 2의 배수로 잡는 경우가 많은데 혹자는 이를 CPU 연산의 효율을 증가시킨다고 합니다. 하지만 111, 234와 같이 아무 배치 사이즈나 잡아도 트레이닝은 잘 합니다.


이러한 배치 트레이닝의 방식을 이해한다면 위의 텐서플로우 코드도 어렵지 않게 이해할 수 있습니다. 


sess = tf.Session()
sess.run(tf.global_variables_initializer())

세션을 만들고 variable을 초기화 시킵니다. 

  • 텐서플로우에서 Variable은 반드시 위와 같이 초기화 시키고 이용해야합니다.

batch_size = 100 # 배치 사이즈 지정
training_epochs = 3 # epoch 횟수 지정


배치 사이즈와 epoch를 정합니다. epoch은 '전체 데이터를 보는 횟수' 입니다.


# epoch 횟수만큼 반복 for epoch in range(training_epochs) : batch_count = int(x_train.shape[0]/100) # 배치의 갯수 for i in range(batch_count) : # 배치를 순차적으로 읽는 루프 # 배치사이즈 만큼 데이터를 읽어옴 batch_xs, batch_ys = x_train[i*batch_size:i*batch_size+batch_size], y_train[i*batch_size:i*batch_size+batch_size] # training, 이를 통해 W, b Variable 값을 조정함 sess.run(train_step, feed_dict = {x : batch_xs, y_ : batch_ys}) # [True False True False False True True ....] 와 같은 boolean vector correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1)) # [1 0 1 0 0 1 1 ...]로 변환 후 평균값을 구하면 accuracy 구할 수 있음 accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float")) # 5번 배치를 읽고 이를 트레이닝한 후 정확도 출력 if i % 5 == 0 : print(str(epoch+1)+' epoch '+ str(i)+' batch ', sess.run(accuracy, feed_dict={x: x_test[0:100], y_: y_test[0:100]}))


이제 마지막 트레이닝 파트입니다. 미니 배치를 구할 때 전체 데이터에서 샘플 데이터를 랜덤으로 뽑는 방식도 있지만 여기서는 그냥 순차적으로 배치를 만들었습니다. 0번부터 100번까지를 1배치, 101번부터 200번까지를 2배치와 같은 방식으로 말입니다. (사실 데이터의 순서에 어떠한 규칙이 있다면 이러한 방식은 좋지 않을 수 있습니다.) epoch만큼 전체 데이터를 보아아햐고 또 배치 사이즈만큼 전체 데이터를 쪼개야하니까 이중 for문을 써야하는 것을 알 수 있습니다. 그리고 두 번째 for문에서는 i라는 인덱스와 batch_size라는 변수를 이용하여 원하는 만큼 데이터를 계속해서 불러온후 Gradient Descent를 하면됩니다. 각각의 문장이 의미하는바는 코드에 주석으로 써두었습니다. 


5. 결과



 배치 트레이닝을 100번 했을 때 이미 정확도가 0.93에 육박하는 것을 알 수 있습니다.




트레이닝이 끝났을 때의 최종 정확도는 0.96 이었습니다. 이미 100번 트레이닝을 했을 때 정확도가 0.93이었기 때문에 그 이상의 training은 의미가 없었을지도 모릅니다. 지금은 validation과정 없이 마구잡이로 트레이닝을 했지만 보통은 언제 training을 끝내야하는지 잘 선택하여야합니다. 계속되는 불필요한 training은 overfitting을 유발할 수 있기 때문입니다. 


반응형
반응형

4p Medicine(4p 의학)은 2000년대 중반에 제안된 것으로 p로 시작하는 4가지 의료 혁신의 목표 예방의료(preventive medicine), 맞춤의료(personalized medicine), 참여의료(participatory medicine), 예측의료(predictive medicine)를 의미하는 약자입니다. 막연한 구호처럼 여겨지던 4p medicine이 최근 디지털 의료, 빅데이터 기술, 유전체 기술의 발달로 인해 차근차근 구현 되어 나가고 있습니다. 


  • Preventive Medicine(예방의료) : preventive medicine은 질병의 치료(disease treatment)와 반대되는 개념으로 질병이 일어나기 전에 미리 방지하는 방법입니다. 질병은 유전적 요인이나 환경적 요인에 영향을 받기 때문에 이것들을 분석함으로써 질병이 발생하기 전에 미리 질병 발생의 확률을 예측할 수 있고 이를 방지할 수 있습니다. 

  • Personalized Medicine(맞춤의료) :  personalized medicine이란 어떠한 개인을 약물에 대한 반응, 질병 위험도 등을 통해 분류하고 이를 통해 개인에 맞춘 의학적인 결정을 내리거나 약을 처방하는 등을 하는 의학적인 절차입니다. 

  • Participatory Medicine(참여의료) : participatory medicine은 환자가 의사와 함께 의학적인 결정에 참여하는 것입니다. 최근 다양한 health care 앱들이 등장함으로써 개인이 의사에 의존하는 정도가 점점 줄고 있습니다.

  • Predictive Medicine(예측의료) : predictive medicine은 질병의 발생 확률을 예측하고, 이를 통해 질병을 방지하거나, 질병이 환자에게 미칠 영향을 유의하게 줄이는 것을 수반합니다. genomics(유전체학), proteomics(단백질체학), cytomics 등 다양한 예측의 방법론이 있는데 가장 기본적인 방법은 유전학으로 미래의 질병을 예측하는 것입니다.

* Personalized Medicine은 Precision Medicine이라고도 불립니다. 


아래는 4p medicine에 대해 이해하기 위해 스크랩한 자료들입니다. 




출처 - https://www.esprevmed.org/news/video-explaining-p4-medicine-preventive-predictive-personalized-participatory/


출처 - http://www.yoonsupchoi.com/2016/02/28/digital-medicine-1/

반응형
반응형

문제

ImportError: No module named cv2


해결


파이썬 opencv 가 설치되어있지 않아서 생기는 문제로 이를 해결하기 위해 conda install opencv, pip install opencv 등을 해보았지만 제대로 되지 않았습니다. 그래서 opencv 홈페이지에서 직접 윈도우즈용 opencv를 설치하였고 설치된 폴더, opencv\build\python\2.7\x64 이곳에서 파이썬 모듈 cv2.pyd를 Anaconda2\Lib\site-packages에 복사하였더니 문제가 해결되었습니다. 

 

http://speark.tistory.com/9


위 블로그를 참고하였습니다.

반응형
반응형

/**

날짜 : 2017/1/30

작성자 : 3개월

텐서플로우 상수, 변수, 플레이스 홀더

**/


어떠한 프로그래밍 언어를 배울 때 해당 언어의 자료구조에 대한 이해는 매우 중요하다. 자료를 대상으로 어플리케이션을 만들거나 예측 모델을 만들기 때문이다. 텐서플로우에서의 자료구조는 크게 상수(Constant), 변수(Variable), 심볼릭변수(placeholder)로 나뉜다. 세 종류는 특성이 모두 다르므로 이를 제대로 아는 것이 중요하다. 아래는 텐서플로우에서 이 자료 구조들을 어떻게 생성하고 다루는지 실습한 것이다. 


1. 상수


기본적인 상수 생성 방법 


""" 텐서플로우 상수
    references : 텐서플로우 첫걸음 &
    https://tensorflowkorea.gitbooks.io/tensorflow-kr/content/g3doc/api_docs/python/constant_op.html
"""
import tensorflow as tf

points = [[1,2,3],[4,5,6]] # 2차원 배열
print(points)

vectors = tf.constant(points) # 텐서플로우 상수 생성

print(vectors) # Tensor("Const_9:0", shape=(2, 3), dtype=int32)
print(vectors.get_shape()) # 2x3

expanded_vectors = tf.expand_dims(vectors, 0) # 2-D 텐서를 3-D 텐서로 차원 확장

print(expanded_vectors) # Tensor("ExpandDims_6:0", shape=(1, 2, 3), dtype=int32)
print(expanded_vectors.get_shape()) # 1x2x3

# value 를 출력하려면 아래와 같이 세션 생성 후 run 해야함
sess = tf.Session()
print(sess.run(vectors)) # [[1 2 3]
                         # [4 5 6]]
print(sess.run(expanded_vectors)) #[[[1 2 3]
                                  # [4 5 6]]]


상수를 생성하는 여러가지 방법


""" 상수를 생성하는 여러가지 방법 """
zeros = tf.zeros_like([4,3,3], dtype=tf.int32, name='zeros')
print(sess.run(zeros)) # [0,0,0] (입력으로 받은 텐서와 같은 shape의 텐서인데 0으로 초기화된 것)

# zeros와 zeros_like의 차이점 잘 비교. 일반적으로 zeros를 많이 쓸거 같음.
zeros2 = tf.zeros([3,4,5], dtype=tf.int32, name='zeros2')
print(sess.run(zeros2)) # 0으로 초기화된 3x4x5 텐서가 만들어짐

ones = tf.ones([2,2,3], dtype=tf.float32)
print(sess.run(ones)) # 1로 초기화된 2x2x3 텐서가 만들어짐

fill = tf.fill([2,3], 9) # 9로 초기화된 2x3 텐서
print(sess.run(fill))

contant = tf.constant([2,3,4]) # 주어진 텐서를 그대로 텐서플로우 변수로 전환
print(sess.run(contant)) # [2 3 4]

tensor = tf.constant(-1.0, shape=[2, 3])# tf.fill([2,3], -1.0) 과 같음
print(sess.run(tensor))


* 난수 상수 생성 -> weight 초기화 할 때 자주 이용


""" 난수 상수 생성 """
# 정규분포 난수
norm = tf.random_normal([2, 3], mean=-1, stddev=4)
print(sess.run(norm))

# 주어진 값들을 shuffle
c = tf.constant([[1, 2], [3, 4], [5, 6]])
shuff = tf.random_shuffle(c)
print(sess.run(shuff))

# 균등분포 난수
unif = tf.random_uniform([2,3], minval=0, maxval=3)
print(sess.run(unif))


시퀀스 상수 생성


""" 시퀀스 """
lin = tf.linspace(10.0, 12.0, 3, name="linspace")
print(sess.run(lin))

# start부터 시작하여 limit까지 (limit는 포함하지 않음) delta의 증가량만큼 확장하며 정수 리스트를 생성합니다.
ran = tf.range(start=3, limit=7, delta=1) 
print(sess.run(ran)) # [3 4 5 6]

# start의 default는 0
ran2 = tf.range(8)
print(sess.run(ran2)) # [0 1 2 3 4 5 6 7]


난수 생성시 Seed의 활용

  • seed를 활용함으로써 매 실행마다 같은 결과를 내도록 할 수 있다.


""" 난수 생성시 seed의 활용 """
a = tf.random_uniform([1], seed=1) # seed를 주고 random한 값을 생성하면 매 session마다 값이 같음
b = tf.random_normal([1])

# Repeatedly running this block with the same graph will generate the same
# sequence of values for 'a', but different sequences of values for 'b'.
print("Session 1")
with tf.Session() as sess1:
  print(sess1.run(a))  # generates 'A1'
  print(sess1.run(a))  # generates 'A2'
  print(sess1.run(b))  # generates 'B1'
  print(sess1.run(b))  # generates 'B2'

print("Session 2")
with tf.Session() as sess2:
  print(sess2.run(a))  # generates 'A1'
  print(sess2.run(a))  # generates 'A2'
  print(sess2.run(b))  # generates 'B3'
  print(sess2.run(b))  # generates 'B4'
    
# tf.set_random_seed를 통해 모든 random value generation function들이 매번 같은 값을 반환함    
tf.set_random_seed(1234)
a = tf.random_uniform([1])
b = tf.random_normal([1])

# Repeatedly running this block with the same graph will generate different
# sequences of 'a' and 'b'.
print("Session 1")
with tf.Session() as sess1:
  print(sess1.run(a))  # generates 'A1'
  print(sess1.run(a))  # generates 'A2'
  print(sess1.run(b))  # generates 'B1'
  print(sess1.run(b))  # generates 'B2'

print("Session 2")
with tf.Session() as sess2:
  print(sess2.run(a))  # generates 'A1'
  print(sess2.run(a))  # generates 'A2'
  print(sess2.run(b))  # generates 'B1'
  print(sess2.run(b))  # generates 'B2'


2. 변수


변수 생성


""" 텐서플로우 변수 
    reference : https://tensorflowkorea.gitbooks.io/tensorflow-kr/content/g3doc/how_tos/variables/
"""
# 두 변수를 생성.
weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35),
                      name="weights")
biases = tf.Variable(tf.zeros([200]), name="biases")

# 변수는 반드시 initialization 해야한다.


변수 초기화

  • 변수는 초기화하지 않으면 사용할 수 없다. 반드시 initialization 하여야 한다.


# 변수 초기화

# 두 변수를 생성
weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35),
                      name="weights")
biases = tf.Variable(tf.zeros([200]), name="biases")

# 변수 초기화 오퍼레이션을 초기화
init_op = tf.global_variables_initializer()

# 나중에 모델을 실행할때
with tf.Session() as sess:
    sess.run(init_op) # initialization 연산 실행
    print(sess.run(weights))
    print(sess.run(biases))


다른 변수값을 참조하여 변수 초기화


# 다른 변수값을 참조하여 초기화 하기

# 랜덤 값으로 새로운 변수 초기화
weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35),
                      name="weights")
# weights와 같은 값으로 다른 변수 초기화
w2 = tf.Variable(weights.initialized_value(), name="w2")
# weights의 2배 값으로 다른 변수 초기화
w_twice = tf.Variable(weights.initialized_value() * 2.0, name="w_twice")

# 변수 초기화 오퍼레이션을 초기화
init_op = tf.global_variables_initializer()

with tf.Session() as sess : 
    sess.run(init_op)
    print(sess.run(w2))
    print(sess.run(w_twice))



3. 플레이스홀더

실행시에 데이터를 제공하는 방법으로 실제 딥러닝 모델 구축시 많이 쓰인다. sess.run 에서 feed_dict에 dictionary 형식으로 값을 넣어주면 되고 이를 feeding이라 한다.


""" 텐서플로우 심볼릭 변수(플레이스홀더)
"""
a = tf.placeholder("float")
b = tf.placeholder("float")

y = tf.mul(a,b)

sess = tf.Session()

print(sess.run(y, feed_dict={a : 3, b: 5})) # 15.0


반응형
반응형

/**

날짜 : 2017.01.30

밑바닥부터 시작하는 딥러닝(한빛미디어) 참고

Softmax 구현 및 성질

*/


Softmax 함수는 3-class 이상의 classification을 목적으로 하는 딥러닝 모델의 출력층에서 일반적으로 쓰이는 활성화 함수(activation function)이다. Softmax 함수는 아래와 같이 나타낼 수 있다.




이를 Latex 표기법으로 나타내면 아래와 같다. (Latex는 라텍스라고 읽으면 안되고 레이택으로 읽는다..)


\begin{align}

y_k = {exp(a_k)}/{\sum_{i=1}^{n}(exp(a_i))}

\end{align}


(위 코드를 Jupyter notebook에서 markdown으로 선택하여 입력 후 run을 누르면 위와 같은 수식이 출력되는 것을 확인할 수 있다. Jupyter notebook에서는 Latex 코드를 수식으로 변환하는 기능을 지원한다.)


""" Softmax 구현 """
import numpy as np

def softmax(a) :
    exp_a = np.exp(a)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    
    return y

a = np.array([0.3, 2.9, 4.0])

print softmax(a) # softmax 결과값 출력
print sum(softmax(a)) # softmax 결과값들의 합은 1이 된다.


Softmax 수식을 그대로 파이썬 코드로 옮기면 위와 같다. 결과가 잘 출력되는 것을 확인할 수 있다. 하지만 Softmax는 수식 안에 e의 지수를 포함하고 있는데, 지수함수는 지수가 커질 수록 매우 큰 폭으로 증가하기 때문에 overflow가 발생하기 쉽다. 아래 코드를 보면 overflow가 발생하는 예와 이를 어떻게 해결하는지를 볼 수 있다.


""" Softmax는 Overflow에 취약하다.
    수식에 e^x 들어가기 때문에 Overflow 범위를 넘어설 수 있다. 
    이를 해결하기 위해서는 Softmax의 성질을 이용한다.
"""
def new_softmax(a) : 
    c = np.max(a) # 최댓값
    exp_a = np.exp(a-c) # 각각의 원소에 최댓값을 뺀 값에 exp를 취한다. (이를 통해 overflow 방지)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    return y
    
a = np.array([1010, 1000, 990]) 
print softmax(a) # overflow
print new_softmax(a) # 정상적으로 출력

# 또한 softmax와 new_softmax 의 결과값을 같다.
test = np.array([1,3,6])
print 'softmax', softmax(test) # [ 0.00637746  0.04712342  0.94649912]
print 'new_softmax', new_softmax(test) # [ 0.00637746  0.04712342  0.94649912]


Softmax를 구현할 때 overflow 가 자주 발생하는 문제를 해결하기 위해 위와 같은 새로운 softmax 함수인 new_softmax를 정의한다. 이는 원소에 어떠한 수를 더하여 exp를 취하더라도 결과 값이 같다는 softmax의 성질을 이용한 것인데, 


위의 등식에서 C를 '원소들의 최댓값의 음수'로 한 것이다. 예를 들어 a = [1010,1000,990] a+c = [0,-10,-20] 이 된다. 이 때, a와 a+c의 softmax 결과값은 같다.



반응형
반응형

/**

날짜 : 2017.01.25

밑바닥부터 시작하는 딥러닝(한빛미디어) 참고

Numpy 기초, 간단한 신경망 구현

*/



numpy 패키지는 데이터 과학, 딥러닝 분야에서 쓰이는 매우 중요한 파이썬 패키지이다. numpy는 거의 표준이라고 불릴만큼 대부분의 사람들이 애용하는 패키지이다. numpy가 쓰이는 가장 큰 목적 중에 하나는 배열, 행렬, 벡터, 텐서와 같은 '다차원 배열'의 구현이다. 많은 사람들이 다차원 배열을 구현할 때 numpy를 이용한다. numpy에서는 이를 ndarray라고 부른다. 또 파이썬의 기본 자료 구조에는 array가 없기 때문에, 꼭 딥러닝이 아니더라도 numpy array는 파이썬에서 1차원 배열을 구현할 때도 쓰인다.


numpy의 기초 문법을 정리하고 이를 이용하여 인풋 2개, 아웃풋 2개, 히든 레이어가 2개(각각 노드수가 3, 2인)인 간단한 신경망을 구현해 보았다.


import numpy as np

A = np.array([1,2,3,4])

print(A)

# 차원출력
np.ndim(A)

# 배열 형상 출력. 튜플로 반환된다.

print A.shape
# (4L,)

print A.shape[0]
# 4


  • 위와 같은 문법을 통해 numpy array를 만들 수 있고, shape, dimension 등을 확인할 수 있다.


""" 2차원 배열 """
B = np.array([[1,2], [3,4], [5,6]])
print(B)

np.ndim(B)

B.shape


  • 2중 대괄호를 쓰면 2차원 배열을 만들 수 있다.


""" 3차원 배열 이상 """
# 2x3x4 배열을 만들고 0으로 초기화
C = np.zeros((2, 3, 4))

print 'C', C

# 아래와 같이 자유롭게 만들 수 있음
D = np.array([[[ 1., 2., 3., 4.],
        [ 0.,  0.,  2.,  0.],
        [ 4.,  0.,  3.,  0.]],
       [[ 1.,  4.,  0.,  6.],
        [ 0.,  0.,  5.,  0.],
        [ 0.,  0.,  0.,  5.]]])

print 'D', D

# 2x2x3x4 4차원 배열
E = np.zeros((2,2,3,4))
print 'E', E


  • 위와 같이 3차원 배열, 4차원 배열 등의 고차원 배열을 만들 수 있다.


""" 내적 """
A = np.array([[1,2], [3,4]])
A.shape

B = np.array([[5,6], [7,8]])
B.shape

np.dot(A,B)

#array([[19, 22],
#       [43, 50]])


  • np.dot 명령어를 통해 두 행렬의 내적(dot product)을 구할 수 있다. 신경망에서 이전층에서 다음층으로 forward 되는 것을 구현할 때 입력과 출력을 행렬의 내적으로 표현할 수 있다.


""" 간단한 신경망 구현 
    입력층에서 1층으로 가는 신호 
    첫 번째 히든 레이어의 노드 수는 3개
"""

def sigmoid(num) : 
    return 1/(1+np.exp(-num))

X = np.array([1.0,0.5]) # 입력이 2개 (x1, x2)
W1 = np.array([[0.1,0.3,0.5],[0.2,0.4,0.6]]) # 입력에 대응하는 weights 
B1 = np.array([0.1,0.2,0.3]) # bias

print X.shape # 1x2
print W1.shape # 2x3
print B1.shape # 1x3

A1 = np.dot(X,W1) + B1
Z1 = sigmoid(A1) # 첫 번째 레이어의 최종 아웃풋

print A1
print Z1


입력층에서 첫 번째 히든 레이어(노드 3개짜리)로 forward하는 것을 구현한 것이다. 입력과 weights, bias는 임의로 정한 것이다. 입력은 x1, x2 이고 각각 1.0,  0.5 이다. weights는 총 6개이다. (이는 input layer의 노드 수 2와 첫 번째 히든레이어의 노드수 3을 곱한 것이다.) bias는 길이 3의 array인데 이를 더해주어 XW에 더하여 XW+B를 만든다. Bias가 왜 필요한지 그리고 신경망에 대한 기본적인 이해는 http://hunkim.github.io/ml/ 홍콩 과기대 김성훈 교수님의 강의를 참조하면 좋다.


""" 1층에서 2층으로 가는 신호 구현
"""
W2 = np.array([[0.1,0.4],[0.2,0.5],[0.3,0.6]])
B2 = np.array([0.1,0.2])

print Z1.shape # 1x3 첫 번째 레이어의 아웃풋이 인풋이 된다.
print W2.shape # 3x2
print B2.shape # 1x2

A2 = np.dot(Z1, W2) + B2
Z2 = sigmoid(A2)


 첫 번째 히든레이어에서 두 번째 히든레이어로 forward하는 것의 구현이다. 첫번째 히든 레이어의 아웃풋 Z1이 인풋이 되었고 위와 같은 방식으로 Z1*W2+B2를 하면 두 번째 히든 레이어의 output을 구할 수 있다.


""" 2층에서 출력층으로 가는 신호 구현
"""

# 출력층의 활성화 함수로 항등함수를 쓴다. 
# 회귀의 경우 출력층의 활성화 함수로 일반적으로 항등항수를  쓴다.
# 2-class classification에서는 sigmoid
# 3-class 이상의 classification에서는 softmax를 쓴다.
def identity_function(x) :
    return x

W3 = np.array([[0.1,0.3],[0.2,0.4]])
B3 = np.array([0.1,0.2])

print Z2.shape # 1x2
print W3.shape # 2x2
print B3.shape # 1x2

A3 = np.dot(Z2, W3) + B3
Y = identity_function(A3)

print Y # 최종 아웃풋 출력 


두 번째 히든 레이어에서 출력층으로 forward 하는 것의 구현이다. 출력층의 activation function은 identity function을 사용하였는데, 이는 '풀고자 하는 문제의 성질' 과 관련이 있다. 회귀에서는 항등함수를, 2클래스 분류에서는 시그모이드를, 다중 클래스 분류에는 소프트 맥스 함수를 사용하는 것이 일반적이다.

반응형
반응형

/**

날짜 : 2017.01.25

밑바닥부터 시작하는 딥러닝(한빛미디어) 참고

activation function 정리

*/


1. Step Function


import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
""" 일반적인 step_function """
def step_function(x) : 
    if x > 0 :
        return 1
    else : 
        return 0

""" numpy의 트릭을 사용한 step function 구현 """
def step_function_np(x) : 
    y = x > 0
    # boolean을 int로 변환하면 True = 1, False = 0이 된다.
    # numpy 배열의 type을 변경할 때 .astype을 쓴다.
    return y.astype(np.int)


첫 번째 step_function의 경우 numpy array를 입력으로 받아들일 수 없다. 반면 step_function_np 함수는 numpy array를 입력으로 받아들일 수 있다. 아래의 경우 y = x > 0 에서 boolean 형식의 numpy array가 반환되는 점을 트릭으로 활용하여 이를 step_function 구현해 활용한 것이다.


실제로 파이썬에서 deep learning 알고리즘을 구현할 때는 일반적으로 numpy array를 입력으로 받아 numpy array를 출력으로 내보내는 함수를 작성하는 것이 편하므로 step_function_np와 같이 구현하는 것이 더 바람직하다.


x = np.arange(-5.0, 5.0, 0.1) # -5.0부터 5.0까지 0.1 간격의 numpy array 생성
y = step_function_np(x)

plt.plot(x,y)
plt.ylim(-0.1,1.1)
plt.show()



2. Sigmoid function


def sigmoid(x) :
    return 1 / (1+np.exp(-x))

x = np.array([-1.0, 1.0, 2.0])

# numpy broadcast 기능으로 인해 정상수행
sigmoid(x)


  • numpy broadcast 기능으로 인해 numpy array에 어떠한 연산을 하면 각각의 element에 연산이 적용된 numpy array가 반환된다.


x = np.arange(-5.0,5.0,0.1)
plt.plot(x, sigmoid(x))
plt.ylim(-0.1,1.1)
plt.show()


  • np.arange는 -5.0 부터 5.0까지 0.1 간격으로 numpy array를 생성해준다.



3. ReLU


def relu(x) : 
    return np.maximum(0, x)


x = np.arange(-5.0,5.0,0.1)
plt.plot(x, relu(x))
plt.show()





반응형
반응형

XECore 설치

https://www.xpressengine.com/download


Autoset 설치

http://autoset.net/xe/download_autoset_9_0_0


  • Autoset9/public_html 폴더에 xe 폴더를 붙여넣고 서버 시작
  • http://127.0.0.1/xe 접속 아래와 같은 화면이 나옴




이후부터 XPress Engine Manual 보고 따라하면 됨


참고 

Autoset 에서 Mysql 이용법



결과

http://127.0.0.1/xe 접속시 아래와 같은 샘플 어플리케이션을 볼 수 있음


반응형
반응형

/**

날짜 : 2017.1.22

작성자 : 3개월

제목 : MNIST 데이터로 CNN Training 해보기

*/



1. 패키지 로드 & 데이터 읽기


""" Simple Convolutional Neural Network for MNIST """
import numpy
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import Flatten
from keras.layers.convolutional import Convolution2D
from keras.layers.convolutional import MaxPooling2D
from keras.utils import np_utils
from keras import backend as K
K.set_image_dim_ordering('th')
import cPickle, gzip, numpy

# Load the dataset
f = gzip.open('mnist.pkl.gz', 'rb')
train_set, valid_set, test_set = cPickle.load(f)
f.close()


필요한 패키지들을 불러오고 데이터들을 불러옵니다.

mnist.pkl.gz는 

https://github.com/mnielsen/neural-networks-and-deep-learning/blob/master/data/mnist.pkl.gz 

에서 다운로드 후 코드와 같은 폴더에 붙여 넣으시면 됩니다.


# train_set 은 튜플로 두 개의 ndsarray를 원소로 가지고 있음
print train_set
print type(train_set)
print len(train_set)

# 튜플을 이렇게 둘로 나눌 수 있음
X_train, y_train = train_set
X_test, y_test = test_set

print type(X_train)
print len(X_train)
print len(y_train)
print X_train
print y_train


이제 MNIST 데이터를 읽어들였고, training set과 test set이 준비 완료되었습니다. 하지만 cnn에서는 x vector의 형태를 알맞게 고치는 preprocessing 작업이 필요합니다.  


2. 데이터 preprocessing


""" In Keras, the layers used for two-dimensional convolutions expect pixel values with the dimensions [pixels][width][height]. """
X_train = X_train.reshape(X_train.shape[0], 1, 28, 28).astype('float32') X_test = X_test.reshape(X_test.shape[0], 1, 28, 28).astype('float32') # normalize inputs from 0-255 to 0-1 X_train = X_train / 255 X_test = X_test / 255 # one hot encode outputs y_train = np_utils.to_categorical(y_train) y_test = np_utils.to_categorical(y_test) num_classes = y_test.shape[1] # fix random seed for reproducibility seed = 7 numpy.random.seed(seed)


위와 같이 numpy의 reshape함수를 이용하여 X vector를 [pixels][width][height] 형태로 바꿔줍니다. (이 때 X_train.shape = (50000L, 784L) 라서 X_train.shape[0] = 50000 입니다.)


  • keras에서 cnn을 구현할 때 [pixels][width][height] 형태로 input을 받습니다. (Theano Backend의 경우)

piexels는 흑백이므로 1을 입력하고 MNIST데이터는 28x28 손글씨 이미지이므로 width = 28, height = 28을 입력합니다. 만약 컬러라면 3을 넣어야합니다. 이제 모든 training 데이터와 test 데이터의 준비는 끝났습니다.


3. CNN 모델 


def cnn_model():
    # create model
    model = Sequential()
    model.add(Convolution2D(32, 5, 5, border_mode='valid', input_shape=(1, 28, 28), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(0.2))
    model.add(Flatten())
    model.add(Dense(127, activation='relu'))
    model.add(Dense(num_classes, activation='softmax'))
    # Compile model
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model


CNN 모델을 구축하여보겠습니다. 

위 모델은 Convolution Layer-ReLU-Pooling Layer-(Dropout)-Fully Connected Network로 이어지는 구조이며 기본적인 CNN의 구조입니다.


  • Convolution2D(32,5,5...)에서 32는 feature map의 갯수라 할 수 있고 5,5는 5x5 필터 사이즈를 의미합니다. 
  • border_mode는 zero-padding에 관한 세팅입니다. valid는 valid convolution을 의미하여 padding을 주지 않습니다. 만약 same인 경우 same convolution이며 zero-padding을 넣어 convolution 결과의 사이즈과 인풋과 같게 합니다.


4. Training & Test


# build the model
model = cnn_model()
# Fit the model
model.fit(X_train, y_train, validation_data=(X_test, y_test), nb_epoch=10, batch_size=200, verbose=2)
# Final evaluation of the model
scores = model.evaluate(X_test, y_test, verbose=0)
print("Baseline Error: %.2f%%" % (100-scores[1]*100))



이제 CNN을 트레이닝해보겠습니다. validation set은 test set으로 대체하였고, epoch=10, batch_size=200으로 하였습니다. verbose는 로깅에 관한 세팅으로 개념을 이해할 때는 무시하셔도 좋습니다.





error는 validation error을 기준으로 하며 마지막 epoch의 validation error에서 (1-0.9370)*100을 하여 6.3%가 됩니다. 앞서 MLP로 training하였을때는 7% 대에 error를 보였지만 CNN을 통해서 error rate를 낮출 수 있었습니다.






반응형
반응형

/**

Keras Mnist Learning Using Multi Layer Perceptron

작성자 : 3개월

날짜 : 2017.1.20

코드하이라이터 : http://markup.su/highlighter/

*/


1. 데이터 읽기


import cPickle, gzip, numpy

# Load the dataset
f = gzip.open('mnist.pkl.gz', 'rb')
train_set, valid_set, test_set = cPickle.load(f)
f.close()


mnist.pkl.gz는

https://github.com/mnielsen/neural-networks-and-deep-learning/blob/master/data/mnist.pkl.gz 

에서 다운로드 후 코드와 같은 폴더에 붙여 넣으시면 됩니다.


cPickle.load(f)를 하면 train_set, valid_set, test_set이 알아서 나뉘어집니다.


# train_set 은 튜플로 두 개의 ndsarray를 원소로 가지고 있음
print train_set
print type(train_set)
print len(train_set)

# 튜플을 이렇게 둘로 나눌 수 있음
X_train, y_train = train_set
X_test, y_test = test_set

print type(X_train)
print len(X_train)
print len(y_train)
print X_train
print y_train


train_set을 위와 같이 X_train, y_train 으로 나눌 수 있습니다.

train_set은 2개의 원소(X, Y)를 갖고 있는 '튜플' 인데 튜플인 경우 저러한 문법이 가능합니다.


2. Multi Layer Perceptron 구현


CNN을 활용하기 전에 Multi Layer Perceptrons을 이용하여 데이터셋을 러닝해봅니다. universal approximation theorem에 의해 사실 이 MLP로도 이미지 classification을 포함한 이 세상에 존재하는 모든 문제를 해결할 수 있습니다. (다만 데이터가 부족할뿐) 


# multi-layer perceptron
import numpy
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.utils import np_utils


패키지를 임포트합니다.


seed = 7
numpy.random.seed(seed)


계속 실행하더라도 동일한 결과를 갖기 위해 numpy random seed를 설정해줍니다.


print type(X_train)
print type(y_train)


타입은 두 개 모두 ndarray입니다. X_train은 784*50000 2차원 배열, y_train은 길이가 50000인 1차원 배열입니다. 784는 MNIST 데이터가 28*28 =784 픽셀 흑백 손글씨 이미지이기 때문에 나온 숫자이고 이를 일렬로 쭉 늘어놓은 것입니다. 또한 50000은 데이터의 갯수입니다. 


# normalize inputs from 0-255 to 0-1
X_train = X_train / 255
X_test = X_test / 255


흑백 이미지 데이터는 픽셀 하나당 0-255까지의 숫자값을 가지므로 이를 255로 나누면 0-1 사이로 normalize됩니다.


# one hot encode outputs
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)

# y_test 의 column을 클래스의 갯수 지정 : 10개
num_classes = y_test.shape[1]
num_pixels = X_train.shape[1]


위와 같이 y 값들을 one hot encoding 합니다.

또 아래 MLP 모델을 구축할 때 쓰는 변수들 num_classes, num_pixels를 정의합니다.


# define baseline model
def baseline_model():
    # create model
    model = Sequential()
    model.add(Dense(num_pixels, input_dim=num_pixels, init='normal', activation='relu'))
    model.add(Dense(num_classes, init='normal', activation='softmax'))
    # Compile model
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model

def good_model():
    # create model
    model = Sequential()
    model.add(Dense(400, input_dim=num_pixels, init='normal', activation='relu'))
    model.add(Dense(100, init='normal', activation='relu'))
    model.add(Dense(num_classes, init='normal', activation='softmax'))
    # Compile model
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model


위와 같이 두 개의 MLP를 만들었습니다.

baseline_model은 히든 레이어가 한 개인 네트워크이고, good_model은 히든 레이어가 두 개인 네트워크입니다.


  • keras의 경우 input layer는 생략하며 첫 번째 히든 레이어에 "input_dim=인풋 레이어의 노드 수"를 지정하는 식으로 네트워크를 구성합니다.
  • 히든 레이어가 많고, 한 레이어당 노드 수가 적을 수록 overfitting이 적어져 generalization이 잘된다고 알려져있습니다.

데이터를 통해 위 두 개의 네트워크를 훈련하고 테스트해보겠습니다.



3. Training & Test


히든 레이어 한 개짜리 MLP


# build the model
model = baseline_model()
# Fit the model
model.fit(X_train, y_train, validation_data=(X_test, y_test), nb_epoch=10, batch_size=200, verbose=2)
# Final evaluation of the model
scores = model.evaluate(X_test, y_test, verbose=0)
print("Baseline Error: %.2f%%" % (100-scores[1]*100))


첫 번째 모델인 baseline_model을 train하고 test하는 코드입니다. 

validation set은 test set으로 대체하였습니다. 

실행시 아래와 같이 10번 epoch을 돌면서, training accuracy, loss와 validation accuracy, loss를 출력합니다. 



error는 validation accuracy를 기준으로하며 (1-0.9232)*100 = 7.68% 입니다.



히든 레이어 두 개짜리 MLP (더 Deep 한 모델)


# build the model
model2 = good_model()
# Fit the model
model2.fit(X_train, y_train, validation_data=(X_test, y_test), nb_epoch=10, batch_size=200, verbose=2)
# Final evaluation of the model
scores = model2.evaluate(X_test, y_test, verbose=0)
print("Baseline Error: %.2f%%" % (100-scores[1]*100))


두 번째 모델인 good_model을 기준으로 training 과 test를 합니다.




위와 같이 Error가 7.54%로 첫 번째 네트워크보다 accuracy가 다소 높은 것을 알 수 있습니다.


4. 결론


MLP로 MNIST 데이터를 training하고 test 해보았습니다. MNIST와 같이 이미지 사이즈가 작고 흑백인 이미지에는 MLP도 꽤 괜찮은 accuracy를 내준다는 것을 알 수 있습니다. 하지만 이미지의 사이즈가 커지고 class의 갯수가 많아질 수록 CNN(Convolutional Neural Network)과 같은 이미지 처리에 최적화된 네트워크를 쓰는 것이 훨씬 효율적일 것입니다. 또한 training할 때 layer와 갯수와 layer당 node수를 적절히 선택하는 것이 중요하며 보통 이 사이즈는 try & error로 구하는 경우가 많습니다. 물론 네트워크를 구성하고 training 해본 경험이 많다면 어느정도의 layer와 node수를 선택해야하는지에 대해 어느정도 직감을 가질 수 있습니다.





반응형