텐서플로우(Tensorflow) - 선형 회귀 (Linear Regression) 구현
이번 포스팅에서는 머신러닝 카테고리에서 포스팅한 선형 회귀에 대한 이해를 바탕으로 텐서플로우로 구현을 해볼 것이다.
텐서플로우는 다음과 같은 처리를 반복한다.
1. 텐서노드와 엣지로 이루어진 그래프를 빌드한다.
2. 세션을 통해서 그래프를 실행 시킨다. ( Session.run() )
3. 실행 결과를 기반으로 텐서 플로우는 다시 그래프를 업데이트 시키기 위해 W(가중치) 값과 b(바이어스) 값을 조절한다.
우리는 선형 회귀 모델에서 H(x) = Wx + b 라는 간단한 식을 알 수 있다.
이 간단한 식을 통하여 구현하게 되는데..
우리는 이와 같은 아주 간단한 데이터 셋이 있다고 하자.
X |
Y |
1 |
1 |
2 |
2 |
3 |
3 |
이에 해당하는 코드를 작성하면 아래와 같다.
1 2 3 4 | import tensorflow as tf x_train = [1,2,3] y_train = [1,2,3] | cs |
그 다음 W(가중치) 값과 b(바이어스) 의 값을 지정해야 하는데 이는 학습을 위해 임의의 값( 아직 잘 모른다고 가정 )을 던져준다.
텐서플로우에서는 가중치와 바이어스에 해당하는 변수를 Variable 을 사용하여 나타낸다. 그리고 텐서 플로우가 알아서 이 값을 자동으로 조절해 줄 것이며 나중에 비용함수가 최소(minimize)가 되는 가중치와 바이어스 값으로 조정하게 된다.
1 2 | W = tf.Variable(tf.random_normal([1]), name="weight") b = tf.Variable(tf.random_normal([1]), name="bias") | cs |
그리고 아래와 같이 간단한 모델을 설계한다.
비용 함수는 아래와 같이 가설 데이터와 실제 데이터의 뺀 값의 2승의 합을 구해 데이터의 개수 만큼 나누는 것이다. ( 머신러닝 카테고리에 비용함수를 구하는 식 참조 )
그 함수로 텐서플로우의 tf.square() 와 tf.reduce_mean() 을 사용한다.
1 2 3 | hypothesis = x_train * W + b cost = tf.reduce_mean(tf.square(hypothesis - y_train)) | cs |
즉, cost가 주어졌을 때 이것을 최소로 하는 값이 가장 적합도가 좋은 것이라 볼 수 있다.
텐서플로우에서는 cost 값을 최소화 하기 위해 최적화 알고리즘인 경사 하강법(Gradient Desent)를 활용한다.
이에 대해서는 나중에 자세히 포스팅 하겠다!
텐서플로우에게 학습도를 0.01로 준 경사 하강법 알고리즘을 실행한다.
(학습률의 값이 너무 크거나 작으면 적합도가 좋은 곳을 찾아갈 수 없기 때문에 보통 이 학습률의 값을 조정해가면서 올바르게 학습이 진행되고 있는지 계속해서 확인하고 변경하게 된다)
1 2 | optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01) train = optimizer.minimize(cost) | cs |
1 2 | sess = tf.Session() sess.run(tf.global_variables_initializer()) | cs |
1 2 3 4 5 | for step in range(2001): sess.run(train) if(step % 20 == 0): print(step,'\t', sess.run(cost),'\t', sess.run(W), '\t', sess.run(b)) | cs |
0 3.71932 [ 0.12182671] [-0.03395895] 20 0.0449641 [ 0.80498177] [ 0.25000292] 40 0.0106179 [ 0.87526667] [ 0.26514038] 60 0.00936938 [ 0.88694853] [ 0.25523993] 80 0.00850695 [ 0.89281565] [ 0.24348839] 100 0.00772613 [ 0.89790565] [ 0.23206855] 120 0.00701699 [ 0.90270871] [ 0.22116441] 140 0.00637294 [ 0.90728158] [ 0.21077074] 160 0.00578801 [ 0.91163903] [ 0.20086528] 180 0.00525677 [ 0.91579169] [ 0.19142532] 200 0.00477427 [ 0.9197492] [ 0.18242902]
1800 2.158e-06 [ 0.99829382] [ 0.00387848] 1820 1.95991e-06 [ 0.99837399] [ 0.00369623] 1840 1.78005e-06 [ 0.99845046] [ 0.00352253] 1860 1.61677e-06 [ 0.99852324] [ 0.00335701] 1880 1.46824e-06 [ 0.99859262] [ 0.00319926] 1900 1.33362e-06 [ 0.99865872] [ 0.00304891] 1920 1.21128e-06 [ 0.99872178] [ 0.00290566] 1940 1.09992e-06 [ 0.9987818] [ 0.00276912] 1960 9.99065e-07 [ 0.99883902] [ 0.00263902] 1980 9.07399e-07 [ 0.99889362] [ 0.00251501] 2000 8.2407e-07 [ 0.99894565] [ 0.00239682]
그렇다면 X와 Y에 해당하는 트레이닝 값을 명시적으로 주지 않을 경우에는 어떻게 할까?
이때는 텐서플로우의 placeholder 를 사용하여 그릇을 만들고 필요할 때 마다 feed 값을 던진다.
아래와 같이 shape를 None으로 설정한 이유는 1차원 데이터 (배열) 가 여러개 들어 올 수 있게 끔 설정 한 것이다.
1 2 | x = tf.placeholder(tf.float32, shape=[None]) y = tf.placeholder(tf.float32, shape=[None]) | cs |
1 2 3 4 | hypothesis = x * W + b cost = tf.reduce_mean(tf.square(hypothesis - y)) optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01) train = optimizer.minimize(cost) | cs |
위와 동일하게 다시 학습을 하는데 학습을 시작하는 시점에 feed 값을 던진다.
1 2 3 4 5 6 | for step in range(2001): _cost, _W, _b, _ = \ sess.run([cost, W, b, train], feed_dict={x:[1,2,3,4,5], y:[2.1,3.1,4.1,5.1,6.1]}) if step % 20 == 0: print(step, _cost, _W, _b) | cs |
이와 같이, 학습 데이터의 파라미터를 던져주어서 학습하게 되었으면 테스트 데이터를 통하여 기대하는 값이 출력 되는지 실행하면.. (X의 파라미터를 던져 Y의 값을 기대해 본다.)
1 2 3 | print(sess.run(hypothesis, feed_dict={x: [5]})) print(sess.run(hypothesis, feed_dict={x: [2.5]})) print(sess.run(hypothesis, feed_dict={x: [1.5, 3.5]})) | cs |
출력 값은 다음과 같다.
오늘도 모두의 딥러닝의 김성훈 교수님께 감사의 말씀 전하면서 포스팅을 마치겠다.
※ 해당 포스팅은 정리의 개념으로 남긴 포스팅이며 조금씩 틀린부분이 있을 수도 있습니다. 지나가다 보시면 댓글로 지적이 나 태클 부탁드립니다.!