본문 바로가기

Artificial Intelligence/Tensorflow

[Tensorflow] 선형회귀분석이 뭐야?

728x90

선형 회귀분석은 하나 이상의 독립변수들이 종속변수에 미치는 영향을 추정할 수 있는 통계기법입니다. tensorflow로 선형 회귀분석방법을 직접 구현해보면서 더 자세하게 알아보겠습니다.

 

다음은 x_data = [1,2,3,4,5,6,7], y_data = [2,3,4,5,6,7,8]의 경우를 점으로 찍은 그래프입니다.

 

<그림 1 점 그래프>

위의 경우에서 주어진 정보를 가장 잘 대변하는 직선 그래프는 무엇일까요? 바로 <그림 2>에서 볼 수 있듯이 y = x + 1입니다.

 

<그림 2 직선 그래프>

이렇듯 선형 회귀분석은 <그림 1>에서 <그림 2>로 가는 과정입니다. 정답과 정보만을 가지고 규칙을 찾을 수 있다는 것이 정말 매력적으로 느껴집니다.

 

다음과 같이 H(x) = wx+b라고 정의하겠습니다.

 

<그림 3 hypothesis>

x와 그에 따른 결과는 이미 알고 있으므로 tensorflow를 활용하여 구해야 하는 값은 w와 b입니다. 최적의 w와 b를 구하기 위해서는 손실이라는 것을 알아야 합니다. 손실은 예측값 H(x)와 실제 값 y의 차이를 나타내는 지표로 아래와 같이 정의됩니다.

 

<그림 4 손실 함수>

다음 그림에서 빨간 부분이 바로 cost값에 해당되는 부분입니다. 최적의 w, b를 구한다는 의미는 손실을 가장 적게 하는 w, b를 구한다는 것과 마찬가지로 생각할 수 있습니다.

 

<그림 5 손실값 시각화>

하지만 <그림 4>는 손실이 양수도 나올 수 있고, 음수도 나올 수 있습니다. 서로 다른 부호를 가지고 있으면 정확한 손실을 계산함에 있어 어려움이 있기 때문에 전부 양수로 바꿔주도록 제곱을 사용합니다. 양수로 변환된 손실 값을 평균을 내어주는 것으로 학습의 방향성을 알 수 있는 지표로 변환시켜줍니다. 식은 다음과 같습니다.

 

<그림 6 바뀐 손실 함수>

예측한 값에 대해서 정확한 값인지 알 수 있는 방법까지 확인하였으므로 다음은 손실 값에 따른 w, b의 값 변경에 대해서 알아보겠습니다. 대표적인 방법으로는 경사 하강법(Gradient Descent)이 있습니다. 경사 하강법은 함수의 기울기를 구하고 기울기의 절댓값이 낮은 쪽으로 이동시키는 방법입니다. 다음은 경사 하강법을 코드로 구현한 것입니다.

 

learning_rate = 0.01

with tf.GradientTape() as tape:
    hypothesis = W * x_data + b
    cost = tf.reduce_mean(tf.square(hypothesis - y_data))
  W_grad, b_grad = tape.gradient(cost, [W, b])
  W.assign_sub(learning_rate * W_grad)
  b.assign_sub(learning_rate * b_grad)

 

여기서 hypothesis는 H(x)에 y_data는 y에 대응됩니다. hypothesis를 정의해주고 <그림 6>의 식을 구현하여 cost에 저장해줍니다. 이렇게 계산된 cost에 대한 변수들(w, b)의 미분 값을 반환하여 줍니다. 반환된 값을 assign_sub와  미분 값을 얼마큼 반영할 것인지 나타나는 learning_rate를 통해 w, b의 값을 갱신해줍니다.

 

x_data = [1,2,3,4,5,6,7]
y_data = [2,3,4,5,6,7,8]

W = tf.Variable(7.0)
b = tf.Variable(5.0)

learning_rate = 0.01
epochs = 1000

for i in range(epochs+1):
  with tf.GradientTape() as tape:
    hypothesis = W * x_data + b
    cost = tf.reduce_mean(tf.square(hypothesis - y_data))
    
  W_grad, b_grad = tape.gradient(cost, [W, b])
  W.assign_sub(learning_rate * W_grad)
  b.assign_sub(learning_rate * b_grad)

  if i % 100 == 0:
    print("{:5}|{:10.4}|{:10.4}|{:10.6f}".format(i, W.numpy(), b.numpy(), cost))

 

앞서 설명한 과정을 코드로 구현하면 위와 같습니다. x와 y값을 주고 임의의 w, b의 값을 설정합니다. 또한 경사 하강법 반영률을 나타내는 learning_rate와 학습 횟수 epochs의 값을 설정해줍니다. 그리고 100번째 학습마다 학습의 진행도를 알 수 있도록 epochs, weight, bias, cost를 출력해줍니다. 출력 결과는 다음과 같습니다.

 

epochs=   0|weight=  4.28|bias=  4.44|cost=928.000000
epochs= 100|weight=0.6334|bias= 2.816|cost=0.664629
epochs= 200|weight=0.7506|bias= 2.235|cost=0.307601
epochs= 300|weight=0.8303|bias=  1.84|cost=0.142363
epochs= 400|weight=0.8846|bias= 1.572|cost=0.065888
epochs= 500|weight=0.9215|bias= 1.389|cost=0.030494
epochs= 600|weight=0.9466|bias= 1.265|cost=0.014113
epochs= 700|weight=0.9637|bias=  1.18|cost=0.006532
epochs= 800|weight=0.9753|bias= 1.122|cost=0.003023
epochs= 900|weight=0.9832|bias= 1.083|cost=0.001399
epochs=1000|weight=0.9886|bias= 1.057|cost=0.000648

 

학습이 진행됨에 따라 cost의 값이 작아지는 것을 확인할 수 있고, y = x + 1에 맞게 w는 1에 가까운 값 b도 1에 가까운 값으로 변경되고 있는 것을 알 수 있습니다. 처음 w=7, b=5일 경우에 직선 그래프를 나타내면 아래의 그림에서 빨간색 직선과 같이 표현됩니다.

 

<그림 7 학습 전 직선그래프>

그렇다면 1,000번의 학습 과정은 직선 그래프에 어떠한 변화를 가져왔을까? 결과는 다음과 같습니다.

 

<그림 8 학습 중 직선 그래프>

 

최초 파란색의 직선에서 청록색의 그래프까지의 변화입니다. <그림 2>와 비교하였을 때 거의 동일한 모습을 하고 있는 것을 알 수 있습니다.

 

선형 회귀의 구현 방법부터 tensorflow를 활용한 구현까지에 대해서 알아보았습니다.

 

참고자료

텐서플로우로 시작하는 딥러닝 기초 강의 - edwith 

728x90