텐서플로우의 예제를 통해서 매우 간단한(질문) 뉴럴 네트워크를 알아 봅시다.

앞서 접해본 [TensorFlow] 001. 맛보기와 내용이랑 유사합니다.

둘 다 y = ax + b 일 때, a와 b를 구하는 방법입니다.

하지만 이 예제의 경우, 구해야 하는 a, b를 weights라는 matrix(2x1) 변수로 선언하고, 임의의 표준정규분포 값을 받아서 그 값에서 a와 b를 유추하는 방식으로 진행됩니다.
아! 그리고 도표를 그리기 시작했습니다. 데이터를 인포그래픽으로 보는 일은 즐거운 일입니다. 

 

weights(b, a) 구하기


y = ax + b

학습 데이터로 x와 y가 주어졌을때, 가중치(weights)로 할당되어 있는 a와 b의 최적의 값을 구해 봅시다.

 

CODE

A simple neural network
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
 
num_examples = 50
# -2에서 4까지, -6에서 6까지 50(num_examples)단계로 꾸준히 증가하는 값을 받아서 2개의 배열로 저장 (직선 상태)
X = np.array([np.linspace(-2, 4, num_examples), np.linspace(-6, 6, num_examples)])
# 꾸준히 증가하는 X 배열에 표준정규분포 값을 각각 넣어줌 (데이터 분산 발생)
X += np.random.randn(2, num_examples)
x, y = X
# x 배열 값에 1을 붙여서 x_with_bias 생성 (1을 붙인 이유는 가중치(weights에서 b, a를 사용할 때, b를 그대로 보존하기 위함) y = b*1 + ax = ax + b
x_with_bias = np.array([(1., a) for a in x]).astype(np.float32)
losses = []
training_steps = 50
learning_rate = 0.002
with tf.Session() as sess:
  # 입력은 x_with_bias(50x2) 사용
  input = tf.constant(x_with_bias)
  # 타겟은 y를 전치행렬(1x50 → 50x1) 설정
  target = tf.constant(np.transpose([y]).astype(np.float32))
  # 가중치 출력 텐서의 모양은 (2x1)으로 정규분포의 분산 0, 표준편차 0.1을 가지는 임의의 값을 초기값으로 설정
  weights = tf.Variable(tf.random_normal([2, 1], 0, 0.1))
  
  # 모든 텐서 변수 초기화
  tf.initialize_all_variables().run()
  
  # input(50x2)과 가중치 값(2x1)을 matrix multiple = yhat은 (50x1) 값이 됨, yhat = 학습 진행중인 데이터
  yhat = tf.matmul(input, weights)
 
  # yhat(50x1)에서 target(50x1) 값을 뺀 값을 yerror로 설정
  yerror = tf.sub(yhat, target)
 
  # 학습중인 weights와 실제 target의 차이의 손실값의 평균 (평균 - reduce_mean)
  loss = tf.reduce_mean(tf.nn.l2_loss(yerror))
  
  # 경사하강법으로 loss가 최소값이 되도록 학습 설정
  update_weights = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
  
  # 50회 학습
  for _ in range(training_steps):
    # 반복적으로 경사하강법을 통해 텐서플로우 변수들을 업데이트 함
    update_weights.run()
    losses.append(loss.eval())
  # 학습이 종료되면 결과 값을 출력
  betas = weights.eval()
  yhat = yhat.eval()
# 그래프로 표현
# fig는 도표를 그릴 영역을 의미함. 도표가 1x2 형태로 가로로 2개 들어감
fig, (ax1, ax2) = plt.subplots(1, 2)
# 도표간 거리는 0.3
plt.subplots_adjust(wspace=.3)
# 그릴 영역의 사이즈는 가로 10, 세로 4
fig.set_size_inches(10, 4)
# 첫번째 도표(ax1)에 입력에 따른 출력 값을 2차원 평면에 점으로 찍음
ax1.scatter(x, y, alpha=.7)
# 첫번째 도표(ax1)에 최종 가중치(weights)를 적용했을 때, 예상되는 target 값을 기준으로 2차원 평면에 점으로 찍음
ax1.scatter(x, np.transpose(yhat)[0], c="g", alpha=.6)
line_x_range = (-4, 6)

# 첫번째 도표(ax1)에 x 값 -4에서 6사이에서 최종 가중치(weights)에 따른 직선 그래프를 그림 betas[0]은 b를 의미 betas[1]은 a를 의미 (yhat = b + a*input)
ax1.plot(line_x_range, [betas[0] + a * betas[1] for a in line_x_range], "g", alpha=0.6)
# 두 번째 도표(ax2)에 학습 진행에 따른 losses를 도식화)
ax2.plot(range(0, training_steps), losses)
ax2.set_ylabel("Loss")
ax2.set_xlabel("Training steps")
plt.show()


Result

 

요약

y  = ax + b 인 상황에서, 입력값 x(input)와 출력값 y(target)을 알고 있다. 이때 최적의 a와 b를 구해보자.

예를 들어 위와 같이 input(coefficient), target(constant) 값이 주어졌을때, x, y를 찾을 수 있다.

하지만, 표준정규분포에 의한 input과 target에 대하여 가장 근접 수렴하는 x, y 값을 찾고자 할 때, 학습(training)을 통해서 최적의 값을 찾을 수 있다.

이때 위 도표의 x와 y를 가중치(weights)로 가져가기 위해서는 y=ax+b에 준하는 행렬(matrix)을 설정해주면 됨. 따라서, b 값을 온전히 보전하기 위해 1을 이용함.

  1. 아래 예와 같이 좌측 행렬 5, 1  들어간 부분이 전부 1이 들어간 형태이고, x는 b(offset), y는 a(기울기)
  2. 하지만 위와 같은 예와 같이 명확히 값이 떨어지지 않는 이유는, matrix(행렬) 입력(input)과 출력(target)이 명확한 수치가 아니라, 분산 값으로 인해서 표준정규분포 값이기 때문임. (Line 10)
  3. 그래서 모든 샘플(exaplmes)에 대하여 가장 수렴할 수 있는 a와 b 값을 찾기 위해서 학습을 해 나가는 과정이 필요함.
  4. 학습이 전개될 때마다 a와 b의 값(weights 2x1 )을 업데이트 시키는데 경사하강법으로 loss가 최소가 되도록 학습을 진행해 나간다.

 

위 변수와 OP 의미 분석

  1. input

    1. constant 타입 : (50x2) 행렬 ( -2 ~ 4 까지 데이터를 균등하게 50개로 쪼개 놓은 값에 표준정규분포 데이터 합산하고 1열의 값을 모두 1로 놓음
    2. input 데이터의 형태가 [1, x] 형태인 이유?
      1. y(target) = ax(input.x) + 1b(input.1) : b를 온전히 보전하기 위해서 1을 사용
  2. weights

    1. variable 타입 : (2x1) 행렬로 값으로 정규분 포분산 0, 표준편차 0.1을 가지는 임의의 값으로 초기 세팅
  3. target

    1. constant 타입 : (50x1) 행렬 초기 분산 데이터 50개가 들어있다. ( -6 ~ 6 까지 데이터를 균등하게 50개로 쪼개 놓은 값에 표준정규분포 데이터 합산)
  4. yhat

    1. 각각의 행렬 input(50x2), weight(2x1)을 곱한 값을 만듬 (50x1)
  5. yerror

    1. yhat(학습중인 값(50x1)에 target 데이터(50x1)과의 차이가 얼마나 나는지에 대한 에러 값을 구함
  6. loss

    1. L2 loss로 reduce_mean... loss 평균을 줄여나간다 의미 같음 (앞으로 자주 만날듯..... 좀 더 지켜보기로)
  7. update_weights

    1. operator 타입 : 경사하강법으로 loss가 최소가 되도록 학습을 진행. 학습에서 필요한 변수(weights가 학습을 통해서 계속 변경됨)
  8. learning_rates

    1. constant 타입 : 왜 학습 비율이 0.002인가? 이 값이 가지는 진정한 의미는 무엇인가?... 이 비율이 적용되는 기준이 무엇인지는 확인이 필요할 것 같음.
  9. plt

    1. plot의 개념으로 보임. fig는 전체 그리는 영역, subplot은 그려지는 도표의 개수를 의미하는 것 같음.
    2. scatter는 값을 점 단위로 그리는 듯 함
    3. yhat scatter와 직선 곡선 그래프는 확인 필요

 

궁금한 점

  1. 로스를 구하는 이유

  2. 경사하강법이란?
  • 레이블 없음