1. Classification
1.1 Summary
분류(Classification)은 데이터를 입력 받아 해당 데이터를 분류하는 모델이다. MNIST, CIFAR가 대표적인 데이터셋이다.
※데이터셋: 딥러닝 모델을 위한 공개된 데이터를 말한다. Ex. MNIST, CIFAR가 대표적이다.
‘0’이 적힌 사진을 0으로 출력한다.
이번 모델은 사진을 분류하는 것은 아니고 털, 날개의 유무에 따라 기타, 포유류, 조류를 분류하는 모델을 만드는 것이 목표이다.
1.2 Source Code
아마 정확도 100%는 나오지 않을 것이다...
# 털과 날개가 있는지 없는지에 따라, 포유류인지 조류인지 분류하는 신경망 모델을 만들어봅니다.
import tensorflow as tf
import numpy as np
# [털, 날개]
x_data = np.array(
[[0, 0], [1, 0], [1, 1], [0, 0], [0, 0], [0, 1]])a
# [기타, 포유류, 조류]
# 다음과 같은 형식을 one-hot 형식의 데이터라고 합니다.
y_data = np.array([
[1, 0, 0], # 기타
[0, 1, 0], # 포유류
[0, 0, 1], # 조류
[1, 0, 0],
[1, 0, 0],
[0, 0, 1]
])
#########
# 신경망 모델 구성
######
X = tf.placeholder(tf.float32)
Y = tf.placeholder(tf.float32)
# 신경망은 2차원으로 [입력층(특성), 출력층(레이블)] -> [2, 3] 으로 정합니다.
W = tf.Variable(tf.random_uniform([2, 3], -1., 1.))
# 편향을 각각 각 레이어의 아웃풋 갯수로 설정합니다.
# 편향은 아웃풋의 갯수, 즉 최종 결과값의 분류 갯수인 3으로 설정합니다.
b = tf.Variable(tf.zeros([3]))
# 신경망에 가중치 W과 편향 b을 적용합니다
L = tf.add(tf.matmul(X, W), b)
# 가중치와 편향을 이용해 계산한 결과 값에
# 텐서플로우에서 기본적으로 제공하는 활성화 함수인 ReLU 함수를 적용합니다.
L = tf.nn.relu(L)
# 마지막으로 softmax 함수를 이용하여 출력값을 사용하기 쉽게 만듭니다
# softmax 함수는 다음처럼 결과값을 전체합이 1인 확률로 만들어주는 함수입니다.
# 예) [8.04, 2.76, -6.52] -> [0.53 0.24 0.23]
model = tf.nn.softmax(L)
# 신경망을 최적화하기 위한 비용 함수를 작성합니다.
# 각 개별 결과에 대한 합을 구한 뒤 평균을 내는 방식을 사용합니다.
# 전체 합이 아닌, 개별 결과를 구한 뒤 평균을 내는 방식을 사용하기 위해 axis 옵션을 사용합니다.
# axis 옵션이 없으면 -1.09 처럼 총합인 스칼라값으로 출력됩니다.
# Y model Y * tf.log(model) reduce_sum(axis=1)
# 예) [[1 0 0] [[0.1 0.7 0.2] -> [[-1.0 0 0] -> [-1.0, -0.09]
# [0 1 0]] [0.2 0.8 0.0]] [ 0 -0.09 0]]
# 즉, 이것은 예측값과 실제값 사이의 확률 분포의 차이를 비용으로 계산한 것이며,
# 이것을 Cross-Entropy 라고 합니다.
cost = tf.reduce_mean(-tf.reduce_sum(Y * tf.log(model), axis=1))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
train_op = optimizer.minimize(cost)
#########
# 신경망 모델 학습
######
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
for step in range(100):
sess.run(train_op, feed_dict={X: x_data, Y: y_data})
if (step + 1) % 10 == 0:
print(step + 1, sess.run(cost, feed_dict={X: x_data, Y: y_data}))
#########
# 결과 확인
# 0: 기타 1: 포유류, 2: 조류
######
# tf.argmax: 예측값과 실제값의 행렬에서 tf.argmax 를 이용해 가장 큰 값을 가져옵니다.
# 예) [[0 1 0] [1 0 0]] -> [1 0]
# [[0.2 0.7 0.1] [0.9 0.1 0.]] -> [1 0]
prediction = tf.argmax(model, 1)
target = tf.argmax(Y, 1)
print('예측값:', sess.run(prediction, feed_dict={X: x_data}))
print('실제값:', sess.run(target, feed_dict={Y: y_data}))
is_correct = tf.equal(prediction, target)
accuracy = tf.reduce_mean(tf.cast(is_correct, tf.float32))
print('정확도: %.2f' % sess.run(accuracy * 100, feed_dict={X: x_data, Y: y_data}))
1.3 One-hot encoding
원-핫 인코딩(One-hot encoding) 자체는 예측 기반의 단어 표현 방법이 아닙니다. 다만, 예측 기반의 단어 표현을 배우기 위해서 반드시 알아야 하는 단어를 표현하는 가장 기본적인 방법입니다.
컴퓨터는 문자보다 숫자를 더 잘 처리 할 수 있다. 이를 위해 우리가 사용하는 자연어를 숫자로 변환화는 여러가지 기법들이 있다. BoW, TDM, TF-IDF는 단어의 빈도를 이용하여 문자를 숫자로 표현하는 방법이다.
https://wikidocs.net/22660 자료를 참고하였습니다.
[‘나는 딥러닝을 좋아하는 개발자이다.']
위 같은 문장이 있으면 형태소 기준으로 자를 수 있을 것이다,
[‘나’, ‘는’, ‘딥러닝’, ‘을’, ‘좋아’, ‘하는’, ‘개발자’, ‘이다']
그 후 토큰화를 수행한다.
{‘나’: 0, ‘는’: 1, ‘딥러닝’: 2, ‘을’: 3, ‘좋아’: 4, ‘하는’: 5, ‘개발자’: 6, ‘이다’: 7}
딕셔너리에서 ‘딥러닝’을 찾으려면
[0, 0, 1, 0, 0, 0, 0, 0]
이런 벡터 형태로 ‘딥러닝’을 찾을 수 있다.
하지만 One-hot encoding도 한계를 가지고 있는데 단어의 갯수가 늘어날 수록, 벡터의 크기가 계속 늘어난다는 단점이 있다. 단어 집합의 크기가 곧 벡터의 차원 수가 된다. 단어가 1000개이면 1000개의 차원을 가진 벡터가 된다. 하나만 1을 가지고, 나머지는 0의 값을 가지는 벡터는 매우 비효율적인 표현 방법이다.
또한 이런 방식은 단어의 유사성을 전혀 표현하지 못한다. 예를 들어서 늑대, 호랑이, 강아지, 고양이라는 4개의 단어에 대해서 원-핫 인코딩을 하면. 강아지와 늑대, 호랑이와 고양이가 유사하다는 것을 표현할 수 없다.
이러한 단점을 없앨 수 있는, 단어의 ‘의미’를 다차원 공간에 벡터화하는 기법으로 총 두가지 종류로 구분해볼 수 있다. 첫째는 카운트 기반으로 단어의 의미를 벡터화하는 LSA, HAL 등이 있으며 둘째는 예측 기반으로 단어의 의미를 벡터화하는 NNLM, RNNLM, Word2Vec, FastText 등이 있습니다. 그리고 두 가지 방법을 모두 사용하는 Glove가 이존재한다.
1.4 tf.nn.relu
relu는 활성화 함수(activation function)중 하나로 0보다 작은 값은 0이 되고 0과 같거나 큰 값은 그대로 넘어 간다. 사용 이유는 그냥 성능이 더 좋기 때문이다.
활성화 함수(activation function)란 인공지능 모델의 표현력을 높이기 위해 사용하는 함수인데, 비선형 분리를 할 수 있어 복잡한 데이터들의 관계를 눈에 더 잘띄게 만들 수 있다.
1.5 Cross-Entropy
전에 배운 MSE를 사용하면 Weight와 Bias의 미분값을 계산하여 정답에 근접 해진다.
이때 sigmoid function을 activation function으로 사용할 경우 z값이 너무 크거나 작아지면 미분값
그래프에서 -6 이하, 6이상인 구간에서 미분값이 0에 가깝다는 것을 확인할 수 있다.
이런 문제 때문에 MSE 대신 Cross-Entropy를 더 활발하게 사용한다.