원래 제 목표가 자비스 만드는 거라(ㄹㅇ) 딥 러닝쪽 공부를 이제서야 시작하게 되었습니다. 원래 여름방학 때부터 하려고 했는데, 그놈의 귀차니즘이.....

이번엔 목표가 제대로 생겨서(고2때 카이스트 입학) 동기부여가 잘 되서, 좀 방향이 잡히더라고요. 여튼 뭐 그래서 제가 공부한 것들 좀 올려보려고 합니다.


일단 앞으로 딥 러닝 공부는 Tensorflow로 할 생각입니다. 제가 Python을 상당히 싫어하지만, 또 써보니 괜찮은 언어이기도 하고 무엇보다 제가 공부하고 있는 곳(http://hunkim.github.io/ml/)을 기준으로 추가적으로 제가 더 찾아보고 그러는 거라서, Tensorflow가 적합한 거 같네요.


- 1. Linear Regression은 무엇인고?


선형 회귀라고도 하며, 두 변수에 대한 선형 관계를 나타낸 것이라고 할 수 있을 듯 합니다.


- 2. Linear Regression을 한 번 해보자!


예를 들어 게임을 하는데 게임을 하는 시간과 그에 따라 얻는 경험치에 대한 표가 있다고 합시다.


 시간(y)

경험치(x)

2

35

60 

70 

100 


그리고 앞으로 게임에서 매일 일정 레벨에 도달하려고 할 때 얼마 만큼의 경험치를 얻기 위해 하루에 몇 시간 정도 게임을 하는 것이 적합한 지에 대해 알고 싶어한다고 합시다. 일반적으로 자연 현상에서는 대부분이 선형 관계이므로 1차 함수꼴(y = ax + b)로 두 변수에 대한 관계를 나타낼 수 있습니다. 따라서 일단 그 관계를 함수로 나타내기 위해서 저 데이터들을 그래프에 나타내봅시다.


이렇게 나옵니다. 이때 저 네 점에 대해 가장 가깝게 지나는 1차 함수를 구해야 합니다. 그래서 나온 것이 최소제곱법입니다. y = ax + b라는 식과 xi, yi 라는 데이터가 있을 때, 최소제곱법의 값은 cost(a, b)라고 하면, 아래와 같은 식이 나옵니다.

이때, 구하고자 하는 가장 최적의 y = ax + b를 만들려면 이때의 cost값이 가장 작아야합니다. TensorFlow에서는 이러한 cost값을 줄여주기 위한 알고리즘으로 GradientDescentOptimizer가 있습니다.  실제로 cost를 줄이는 알고리즘을 구현하고자 하면 조금 까다롭긴 하지만 크게 어렵지는 않습니다.


먼저 y = ax + b에서 우리는 cost를 줄이기 위해 a, b를 변수로 두고 이를 조정해야합니다. 위의 cost(a, b)식을 전개하면 다음과 같이 나옵니다.


휴... 전개가 좀 힘드네요. 여튼 잘 보시면 이 식은 간단하게 z = ax2 + by2 + cxy + d(a, b, c, d는 상수)의 함수꼴로 나타낼 수 있습니다. 일단 cost 함수를 위의 예시대로 데이터를 넣어서 전개해봅시다.

그리고 이 식대로 그래프를 한 번 그려봅시다. (식이 조금 복잡한 관계로, 다른 그래프들과 달리 https://academo.org/demos/3d-surface-plotter/를 사용했습니다.)



?! 아닛, 3D 포물면을 보는 기분이군요(WolframAlpha에서도 같은 함수를 돌렸는데 포물면인가 뭐시기라고 나온 거 같네요) 근데 사실 정확히 포물면은 아니고, 저기에 마우스 대서 값을 보면 최솟값인 부분이 한 군데로 수렴하는 거 같습니다. 뭐 여튼, 이때 cost의 최솟값 부분을 찾아야 하니 이 함수를 미분해서 0인 부분을 찾으면 됩니다! (아마 고등학교 과정의 미적분 수준으로는 힘들 거 같고, 편미분으로 할 수 있지 않을까 싶네요) 편미분으로 하는 과정은 다음 글에 한 번 써보도록 노력을 해보겠습니다. 


일단 본래 목적은 TensorFlow에서 GradientDescentOptimizer를 통해 cost를 줄여, 최종적인 1차 함수꼴을 얻는게 목적이니 이제 TensorFlow를 사용해봅시다. 소스 코드는 다음과 같습니다.

import tensorflow as tf import matplotlib.pyplot as plt x_data = [35, 60, 70, 100] y_data = [2, 4, 5, 9] W = tf.Variable(tf.random_uniform([1], -2.0, 2.0)) b = tf.Variable(tf.random_uniform([1], -2.0, 2.0)) y = W * x_data + b loss = tf.reduce_mean(tf.square(y - y_data)) optimizer = tf.train.GradientDescentOptimizer(0.0002) train = optimizer.minimize(loss) init = tf.initialize_all_variables() sess = tf.Session() sess.run(init) for step in xrange(300001): sess.run(train) if step % 60000 == 0: print(step, sess.run(W), sess.run(b)) print(step, sess.run(loss)) # Graph plt.plot(x_data, y_data, "go") plt.plot(x_data, sess.run(W) * x_data + sess.run(b)) plt.axis([0, 110, 0, 10]) plt.show()

문제는 GradientDescentOptimizer의 특성인지, learning_rate를 0.0002정도로 세팅해야지, 이 이상으로 세팅하면 값이 수렴하지 않고 오히려 INF로 넘어가서 아예 함수를 못 만들게 되는 현상이 일어납니다... learning_rate를 아주 작게 세팅하니 그만큼 수렴 속도도 무진장 느리고요... 원인 파악은 못 했으나 GradientDescentOptimizer 대신 TensorFlow의 다른 Optimizer를 시험삼아 써봤더니 아주 아주 조금 부정확하지만 빨리 수렴하더라고요 흠... 연구가 많이 필요해보입니다. 아마 다음 글에서 편미분하고 알고리즘 직접 작성하면서 알게될 수 있을지도 모르겠다는 생각이 드네요.


그리고 제가 GPU 세팅된 TensorFlow 버전을 사용하는데도 다 돌리는데 1분 넘게 걸리니 웬만하면 step을 1천 정도로 잡아주시는게 간단히 보는데 좋을 거 같습니다. 굳이 좋게 하실려면 GradientDescentOptimizer 대신 AdamOptimizer(0.5)를 돌려주시면 깔끔하게 나올 겁니다. (저건 또 왜인지 모르겠지만 무진장 좋긴 한데, 로그를 보시면 값이 수렴하지 않고 마지막까지 조금씩 바뀌기도 하더군요)


그래프의 변화도 첨부하고 싶었는데, 좀 노잼이여서(... 겁나 느리게 수렴합니다) 그냥 마지막 그래프만 보여드리겠습니다.


Linear Regression은 뭐 이정도면 얼추 끝난 거 같습니다. 다음 글에서는 위에서 말한 편미분을 통한 cost 줄이기 알고리즘을 직접 설계해서 돌려보도록 하겠습니다. 그 다음엔 다중 Linear Regression? 뭐 이런 걸 할 거 같네요. (위에 언급한 머신러닝 강의 순서대로 공부하고 글을 쓸 예정입니다)

+ Recent posts

티스토리 툴바