본문 바로가기

유니티 ML Agents/머신러닝과 강화학습 코딩

6. 텐서플로우 단일 신경망

회귀분석 모델 전체 코드


데이터를 이진 분류하는 기본적인 인공신경망을 만들어보자. 이진 분류를 하기 위해서는 먼저 데이터를 나눌 수 있는 일차 함수를 찾고 다시 시그모이드 함수를 통해 결과를 분류해야 한다.


테스트 데이터 생성을 위해 sk-learn 패키지에서 제공하는 make_classfication함수를 사용해보자. (1) 인수로 들어가는 n_featuresn_informative는 몇 개의 분류로 나눌 것인지 결정한다. 2로 설정했기 때문에 이진 분류 데이터를 생성한다. (2) 특징은 x1x2개 이고 데이터에 대한 분류 정보는 y에 들어간다. (3) scatter 그래프를 통해 데이터 분포를 살펴보면 흰색과 검은색 데이터가 명확하게 분류되어 있는 것을 확인할 수 있다.


모델 생성 및 손실함수 정의


데이터를 분석하고 가공하기에는 pandas의 데이터프레임 형식이 좀 더 효율적이지만, 텐서플로우에서는 넘파이 형식의 데이터가 좀 더 다루기 편리하다. (1) 입력 데이터와 출력 데이터를 먼저 numpy 형식으로 변환하자. 데이터프레임 뒤에 values만 붙여주면 numpy 형식의 데이터를 얻을 수 있다.


학습 데이터를 임시로 저장할 플레이스홀더를 선언한 후에 (2) 가중치와 편향을 선언하자. 단순 인공신경망의 경우 학습이 불완전하기 때문에 랜덤으로 가중치와 편향을 설정하면 학습이 제대로 되지 않을 수 있다. 따라서 어느 정도 학습 성능을 확인할 수 있는 초기 값을 설정해 주도록 한다.


(3) 학습 대상이 되는 선형 함수를 선언한다. Y = W*X +a와 동일하게 함수를 선언한다. (4) 이제 선형 함수의 결과를 이진 분류할 수 있는 활성화 함수를 선언한다. 다양한 활성화 함수가 있지만 여기에서는 relu 함수를 사용하도록 하자.


(5) 이진 분류 결과의 합을 1로 변환해 주는 softmax 함수를 통해 결과 값을 다시 한 번 가공하도록 한다. 결과의 합이 1이 된다는 얘기는 결국 확률을 반환해 준다는 얘기가 된다. 예제에서는 Y 값의 종류가 01 두 개 있으므로 softmax0일 확률과 1일 확률을 각각 반환한다. 둘 중 큰 것이 모델에서 예측한 결과가 된다.


(6) 손실함수를 선언한다. 분류 학습에서는 손실함수는 교차 엔트로피(Cross Entropy) 함수를 사용한다. 교차 엔트로피값은 예측 값과 실제 값의 확률 분포 차이를 계산한 값이다. 교차 엔트로피 값은 결과 값이 01로만 이루어져 있을 때 사용하며 오류가 발생하면 오류의 크기가 지수함수적으로 증가하는 특징을 가지고 있다. reduce_sum(matrix, axis=1) 하면 하나의 차원만 남기고 다른 차원의 값을 모두 합산한다는 의미이며 reduce_mean(matrix)하면 하나 남은 차원 값에 대한 평균을 구하기 때문에 결국 오차가 많이 발생하면 손실함수의 값도 커지게 된다.



모델 학습

(1) 학습은 총 5000번 진행하고 매 500번 학습마다 화면에 로그를 찍는다. (2) 학습이 종료되면 결과를 확인하기 argmax 함수를 사용해서 모델 결과 값 중 가장 확률이 높은 것을 찾는다. (3) run 함수를 사용해 입력 값에 따른 예측 결과를 출력한다.


결과비교


(1) 모델의 정확도를 계산하기 위해 먼저 실제 값인 Y 데이터를 정수형으로 변환해야 한다. 앞에서 Y는 실수형으로 선언됐고 모델에서 예측하는 값인 prediction은 정수형으로 나오기 때문이다. 텐서플로우의 equal 함수를 사용하면 맞을 경우 True를 틀리면 False를 출력한다.


(2) TrueFalse 값을 배열로 가지고 있는 is_correct 함수를 실수형으로 형변환하면 Ture1.0으로 False0.0으로 변환되고 여기에 reduce_mean 함수를 실행하면 평균 즉 정확도가 출력된다.


(3) y_array를 그대로 출력하면 한 줄로 쭉 나와 보기 안좋기 때문에 데이터의 모양을 바꿔준다.


테스트 데이터를 무작위로 생성해서 학습할 때마다 결과 값이 약간 다를 수 있지만 예제의 정확도는 약 55% 정도로 나왔다.




import tensorflow as tf
import pandas as pd
from sklearn.datasets import make_classification
X, y = make_classification(n_features=2, n_informative=2, n_redundant=0, n_clusters_per_class=1, random_state=2)
df = pd.DataFrame(dict(x1=X[:,0], x2=X[:,1], y=y))
df.plot.scatter(x='x1', y='x2', c=y, s=100, edgecolor="k", linewidth=2)
x_array = df[['x1','x2']].values
y_array = df[['y']].values
X = tf.placeholder(tf.float32, name="X")
Y = tf.placeholder(tf.float32, name="Y")
w = tf.Variable([[0.04], [0.03]], name='w')
a = tf.Variable([[0.02, 0.05]], name='a')
L = tf.add(tf.matmul(X, w), a)
L = tf.nn.relu(L)
model = tf.nn.softmax(L)
cost = tf.reduce_mean(-tf.reduce_sum(Y*tf.log(model), axis=1))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.0001)
trainnig = optimizer.minimize(cost)
sess = tf.Session()
sess.run(tf.global_variables_initializer())
for step in range(15000):
none, cost_val = sess.run([trainnig, cost], feed_dict={X: x_array, Y: y_array})
if(step % 500 == 0):
print(step, cost_val)
prediction = tf.argmax(model, axis=1)
result = sess.run(prediction, feed_dict={X: x_array})
print("예측값:", result)
sess.close()