Linear Regression의 Hypothesis와 cost의 개념 연습
Hypothesis와 cost(loss) 함수
- 가설(hypothesis) : 주어진 \(x\)에 대해서 예측(\(H(x)\))을 어떻게 할 것인가?
- weight \(W\)와 bias \(b\)로 표현된다.
$$H(x) = Wx + b$$
- cost(loss) 함수 : 예측을 얼마나 잘 했는가?를 표현한 것으로 차이의 제곱에 대한 평균
- \(H(x_i)\) : 예측값
- \(b_i\) : 실제값
$$\textrm{cost(loss)}(W,b)=\frac{1}{m}\sum_{i=1}^{m}(H(x_i)-b_i)^2$$
- 학습을 한다는 것
- \(W\)와 \(b\)를 조절해서 cost(loss) 함수의 가장 작은 값을 찾아내는 것
cost(loss) 함수를 TensorFlow로 구현하는 방법
- TensorFlow의 연산을 사용하여 그래프를 만든다.
- Session() 함수로 세션을 만들고, sess.run() 함수에 데이터를 주고 계산 그래프를 실행하여 연산을 한다.
- 결과값이 나와 그래프에 있는 변수들이 업데이트되거나 값을 반환한다.
1. TensorFlow의 연산을 이용하여 그래프 만들기
- 예측값에 대한 함수 \(H(x)=Wx+b\)를 TensorFlow로 작성해보자.
- TensorFlow에서는 weight \(W\)와 bias \(b\)의 값을 변수(variable) node로 정의
- 기존 프로그래밍의 변수와는 다른 개념
- TensorFlow가 사용하는 변수
- 프로그램을 실행하면 TensorFlow가 자체적으로 변경시키는 값을 의미
- 학습을 위해 TensorFlow가 변경을 하면서 최적의 값을 찾아낸다.
- TensorFlow 변수를 만들 때에는 변수의 shape을 정의하고 값을 주어야 한다.
- 보통 \(W\)와 \(b\)의 값을 모르기 때문에 random한 값을 준다.
- tf.random_normal(shape)
- 예측값 함수를 TensorFlow의 한 점(node)으로 정의
- tensor 또는 node \(W\)와 \(b\)로 표현
import tensorflow as tf # 학습용 X와 Y 데이터를 준다. x_train = [1, 2, 3] y_train = [1, 2, 3] # TensorFlow 변수를 1차원 배열로 정의 w = tf.Variable(tf.random_normal([1]), name = 'weight') b = tf.Variable(tf.random_normal([1]), name = 'bias') # 예측값 함수(hypothesis) hypothesis = w * x_train + b
- cost(loss) 함수 \(\textrm{cost(loss)}(W,b)=\frac{1}{m}\sum_{i=1}^{m}(H(x_i)-b_i)^2\)를 TensorFlow 함수를 이용해 표현해보자.
- tf.reduce_mean() 함수 : tensor가 주어졌을 때 평균을 구하는 함수
- cost(loss) 함수의 평균을 내는 부분 \(\frac{1}{m}\sum_{i+1}^{m}\)을 구현하는 것
>>> import tensorflow as tf >>> t = [1., 2., 3., 4.] >>> r_mean = tf.reduce_mean(t) >>> sess = tf.Session() >>> print("sess.run(r_mean) = ", sess.run(r_mean)) sess.run(r_mean) = 2.5
cost(loss) 함수 \(\textrm{cost(loss)}(W,b)=\frac{1}{m}\sum_{i=1}^{m}(H(x_i)-b_i)^2\)는 다음과 같이 작성할 수 있다.
# cost(loss) 함수 cost = tf.reduce_mean(tf.square(hypothesis - y_train))
- 이제 cost(loss) 함수를 최소화(minimization)해야 한다.
- TensorFlow에서는 GradientDescentOptimizer() 함수를 사용한다
- 학습 최적화를 위해 minimize() 함수를 사용해 cost 함수의 최소값을 찾도록 한다.
- 이 부분이 magic이 되는 부분이다.
# GradientDescentOptimizer() 함수로 학습에 Gradient Descent 최적화 방법을 사용 optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01) train = optimizer.minimize(cost)
- TensoFlow 세션을 만들고 실행해야 한다.
- tf.session() 함수를 만든다.
- 그래프에 있는 전역 변수를 초기화한다.
- weight $W$와 bias $b$는 앞에서 선언했다.
- 변수를 사용하기 위해서는 반드시 초기화를 해주어야만 한다.
- tf.global_variables_initializer() 함수로 변수를 초기화할 수 있다.
# 세션을 만든다. sess = tf.Session() # 그래프에 있는 모든 전역 변수를 초기화한다. sess.run(tf.global_variables_initializer())
- training 점 : cost 함수를 최소화시킬 수 있다.
- train을 실행시켜야 cost를 최소화시킬 수 있다.
- cost를 최소화시킨다는 것은 예측값과 실제값의 차이를 최쇠화시킨다는 것이다.
- 세션을 통해 train 점을 실행시킬 수 있다.
- sess.run(train) 함수를 통해 학습이 이루어진다.
- 예제에서는 2만번 학습을 한다.
- 매번 결과를 출력하지 않고, 2000번째 마다 학습한 값을 출력한다.
for step in range(20001): sess.run(train) if step % 2000 == 0: # sess.run(train) 실행을 통해 그래프 상의 모든 연산이 수행되어 # 그래프 상의 변수의 값들이 업데이트된다. print(f"STEP = {step:>5}, cost = {sess.run(cost):>.10}, " f"weight = {sess.run(W)}, bias = {sess.run(b)}")
2.3. 그래프의 변수들이 업데이트 된다.
- 프로그램의 실행 결과는 다음과 같다.
- 예제 학습 데이터를 통해 우리가 예측할 수 있는 것은 weight \(W=1\)이고, bias \(b=0\)이다.
- 실제 학습을 시킨 후의 결과는 \(W\approx 1\), \(b\approx 0\)이다.
STEP = 0, cost = 2.450398445, weight = [ 0.52071428], bias = [-0.55709851] STEP = 2000, cost = 7.966009434e-07, weight = [ 1.00103676], bias = [-0.00235626] STEP = 4000, cost = 6.939634284e-11, weight = [ 1.00001001], bias = [ -2.18230052e-05] STEP = 6000, cost = 1.227817847e-11, weight = [ 1.00000429], bias = [ -8.61254284e-06] STEP = 8000, cost = 1.227817847e-11, weight = [ 1.00000429], bias = [ -8.61254284e-06] STEP = 10000, cost = 1.227817847e-11, weight = [ 1.00000429], bias = [ -8.61254284e-06] STEP = 12000, cost = 1.227817847e-11, weight = [ 1.00000429], bias = [ -8.61254284e-06] STEP = 14000, cost = 1.227817847e-11, weight = [ 1.00000429], bias = [ -8.61254284e-06] STEP = 16000, cost = 1.227817847e-11, weight = [ 1.00000429], bias = [ -8.61254284e-06] STEP = 18000, cost = 1.227817847e-11, weight = [ 1.00000429], bias = [ -8.61254284e-06] STEP = 20000, cost = 1.227817847e-11, weight = [ 1.00000429], bias = [ -8.61254284e-06]
TensorFlow의 전체적인 구조
- train() 함수는 cost() 함수와 연결되어 있다.
- cost() 함수는 hypothesis \(H(x)\)와 연결되어 있다.
- \(H(x)\)는 weight \(W\)와 bias \(b\)의 형태로 연결되어 있다.
- train()을 실행시킨다는 것은
- 아래 그림과 같은 그래프를 만든 다음에 training을 한다.
- train() 함수 실행 : 학습을 시킨다는 것
- 그래프를 따라 들어가 \(W\)와 \(b\)에 값을 저장한다는 것을 의미
- 학습을 통해 cost(loss) 함수의 값과 weight \(W), bias \(b)의 값을 보게된다.
- 예제의 전체 소스코드
import tensorflow as tf # 학습용 X와 Y 데이터를 준다. x_train = [1, 2, 3] y_train = [1, 2, 3] # TensorFlow 연산에서는 weight와 bias를 variable로 정 W = tf.Variable(tf.random_normal([1]), name = 'weight') b = tf.Variable(tf.random_normal([1]), name = 'bias') # 예측값 함수(hypothesis) hypothesis = W * x_train + b # cost(loss) 함수 cost = tf.reduce_mean(tf.square(hypothesis - y_train)) # GradientDescentOptimizer() 함수로 학습에 Gradient Descent 최적화 방법을 사용 optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01) train = optimizer.minimize(cost) # 세션을 만든다. sess = tf.Session() # 그래프에 있는 모든 전역 변수를 초기화한다. sess.run(tf.global_variables_initializer()) for step in range(20001): sess.run(train) if step % 2000 == 0: # sess.run(train) 실행을 통해 그래프 상의 모든 연산이 수행되어 # 그래프 상의 변수의 값들이 업데이트된다. print(f"STEP = {step:>5}, cost = {sess.run(cost):>.10}, " f"weight = {sess.run(W)}, bias = {sess.run(b)}")
placeholder() 함수로 실행할 때 변수의 값을 줄 수 있다.
그래프를 미리 만들어 놓고, 실행하는 단계에서 값을 주고 싶다.
placeholder() 함수로 점을 만들어 놓으면 된다.
- placeholder() 함수로 변수형 점을 만든다.
- run() 함수로 그래프를 실행할 때, feed_dict 변수로 데이터를 입력한다.
placeholde() 함수를 사용해 변수를 선언
# 프로그램을 실행할 때 변수의 값을 넣기위해 placeholde() 함수를 사용 X = tf.placeholder(tf.float32) Y = tf.placeholder(tf.float32)
- 실행 단계에서 feed_dict 옵션을 사용하여 데이터를 입력
- X = [1, 2, 3, 4, 5]
- Y = [2.1, 3.1, 4.1, 5.1, 6.1]
- \(W=1\), \(b=1.1\)
for step in range(20001): cost_val, W_val, b_val, _ = \ 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 % 2000 == 0: print(f"STEP = {step:>5}, cost = {cost_val:>.15}, " f"weight = {W_val}, bias = {b_val}")
- placeholde() 함수를 사용하는 전체 코드
import tensorflow as tf # 프로그램을 실행할 때 변수의 값을 넣기위해 placeholde() 함수를 사용 X = tf.placeholder(tf.float32) Y = tf.placeholder(tf.float32) W = tf.Variable(tf.random_normal([1]), name = 'weight') b = tf.Variable(tf.random_normal([1]), name = 'bias') hypothesis = W * X + b cost = tf.reduce_mean(tf.square(hypothesis - Y)) optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01) train = optimizer.minimize(cost) sess = tf.Session() sess.run(tf.global_variables_initializer()) for step in range(20001): cost_val, W_val, b_val, _ = \ 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 % 2000 == 0: print(f"STEP = {step:>5}, cost = {cost_val:>.15}, " f"weight = {W_val}, bias = {b_val}")
- 실행 결과
- \(W\approx1\), \(b\approx1.1\)
STEP = 0, cost = 121.828224182129, weight = [-1.6607039], bias = [ 1.53716469] STEP = 2000, cost = 2.85170699498849e-07, weight = [ 0.99965453], bias = [ 1.10124719] STEP = 4000, cost = 6.18001622099129e-11, weight = [ 0.99999481], bias = [ 1.10001838] STEP = 6000, cost = 6.18001622099129e-11, weight = [ 0.99999481], bias = [ 1.10001838] STEP = 8000, cost = 6.18001622099129e-11, weight = [ 0.99999481], bias = [ 1.10001838] STEP = 10000, cost = 6.18001622099129e-11, weight = [ 0.99999481], bias = [ 1.10001838] STEP = 12000, cost = 6.18001622099129e-11, weight = [ 0.99999481], bias = [ 1.10001838] STEP = 14000, cost = 6.18001622099129e-11, weight = [ 0.99999481], bias = [ 1.10001838] STEP = 16000, cost = 6.18001622099129e-11, weight = [ 0.99999481], bias = [ 1.10001838] STEP = 18000, cost = 6.18001622099129e-11, weight = [ 0.99999481], bias = [ 1.10001838] STEP = 20000, cost = 6.18001622099129e-11, weight = [ 0.99999481], bias = [ 1.10001838]
- 훈련시킨 모델로 값을 예측해보자.
- 전체 소스 코드 뒤에 모델로 다른 값에 대한 예측값을 계산하는 코드를 추가한다.
print("X = {:4}일 때의 예측값은 {}입니다.".format(5, sess.run(hypothesis, feed_dict={X: [5]}))) print("X = {:4}일 때의 예측값은 {}입니다.".format(2.5, sess.run(hypothesis, feed_dict={X: [2.5]}))) print("X = [ {}, {} ]일 때의 예측값은 {}입니다.".format(1.5, 3.5, sess.run(hypothesis, feed_dict={X: [1.5, 3.5]})))
- 예측값은 다음과 같이 실제 데이터와 거의 같게 나온다.
- \(x=5\)일 때, \(H(5)\approx6.1\)
- \(x=2.5\)일 때, \(H(2.5)\approx3.6\)
- \(x=[1.5, 3.5]\)일 때, \(H(x)\approx[2.6, 4.6]\)
X = 5일 때의 예측값은 [ 6.09999275]입니다. X = 2.5일 때의 예측값은 [ 3.60000563]입니다. X = [ 1.5, 3.5 ]일 때의 예측값은 [ 2.60001063 4.60000038]입니다.
예제 모델에 대한 TensorFlow 역학 구조
cost(loss) 함수의 그래프 그리기
matplotlib 모듈을 이용하여 $W$에 대한 cost(loss) 함수의 그래프 그리기
import tensorflow as tf import matplotlib.pyplot as plt # 학습용 데이터 X와 Y X = [1, 2, 3] Y = [1, 2, 3] W = tf.placeholder(tf.float32) # 우리의 가설은 bias b를 생략했다. 즉 H(W) = W * X hypothesis = W * X # cost(또는 loss) 함수는 가설과 y 값과의 차의 제곱에 대한 평균 cost = tf.reduce_mean(tf.square(hypothesis - Y)) # 세션에서 그래프 활성화 sess = tf.Session() # 변수 초기화 sess.run(tf.global_variables_initializer()) # cost(loss) 함수를 그래프로 출력하기 위한 변수설정 W_val = [] cost_val = [] # W 범위 -30부터 50까지에 대하여 cost(loss) 함수의 값을 구하여 저장 for i in range(-30, 50): feed_W = i * 0.1 curr_cost, curr_W = sess.run([cost, W], feed_dict={W: feed_W}) W_val.append(curr_W) cost_val.append(curr_cost) # matplotlib 모듈을 이용하여 cost(loss) 함수 그리기 plt.plot(W_val, cost_val) plt.show()
- 위 코드 실행 결과는 아래 그래프 처럼 볼록 함수의 그래프로 표시된다.
- 이제 아래 그래프에서 극소값을 찾아야 한다.
cost(loss) 함수의 극소값 찾기
- 기울기(경사도)는 미분을 이용하여 찾는다.
- 오른쪽은 기울기가 양(+, positive)이고, 왼쪽은 음(-, negative)
- 기울기가 양이면 왼쪽으로 움직여야 하기 때문에 기울기를 빼준다.
- 기울기가 음이면 오른쪽을 움직여야 하기 때문에 기울기를 더해준다.
- 아래 식 (1)을 코드로 구현
- \(\alpha\) : learning rate = 0.1
- \(\nabla=\frac{1}{m}\sum(Wx_i-y_y)x_i\) : gradient
- 경사 하강법 : descent = W - learning_rate * gradient
\begin{equation}W = W - \alpha\frac{1}{m}\sum_{i=1}^m(W x_i - y_i) x_i\tag{1}\end{equation}
import tensorflow as tf x_data = [1, 2, 3] y_data = [1, 2, 3] W = tf.Variable(tf.random_normal([1]), name='weight') X = tf.placeholder(tf.float32) Y = tf.placeholder(tf.float32) # 가설은 H(W) = W * X hypothesis = W * X # cost(loss) 함수 cost = tf.reduce_mean(tf.square(hypothesis - Y)) # 미분계수(기울기=경사도)로 경사 하강법을 사용 # W = W - learning_rate * 미분계수(gradient) learning_rate = 0.1 gradient = tf.reduce_mean((W * X - Y) * X) descent = W - learning_rate * gradient update = W.assign(descent) # 세션에서 그래프 활성 sess = tf.Session() # 변수 초기화 sess.run(tf.global_variables_initializer()) for step in range(21): sess.run(update, feed_dict={X: x_data, Y: y_data}) print(f"STEP = {step:02}, cost(loss) 함수값 = {sess.run(cost, feed_dict={X: x_data, Y: y_data}):>.5}," f"기울기 = {sess.run(W)} ")
실행 결과
STEP = 00, cost(loss) 함수값 = 0.604494512081146240234375,기울기 = [ 1.35990906] STEP = 00, cost(loss) 함수값 = 15.124,기울기 = [-0.80024123] STEP = 01, cost(loss) 함수값 = 4.302,기울기 = [ 0.03987139] STEP = 02, cost(loss) 함수값 = 1.2237,기울기 = [ 0.4879314] STEP = 03, cost(loss) 함수값 = 0.34807,기울기 = [ 0.72689676] STEP = 04, cost(loss) 함수값 = 0.099005,기울기 = [ 0.85434496] STEP = 05, cost(loss) 함수값 = 0.028161,기울기 = [ 0.92231733] STEP = 06, cost(loss) 함수값 = 0.0080104,기울기 = [ 0.95856923] STEP = 07, cost(loss) 함수값 = 0.0022785,기울기 = [ 0.9779036] STEP = 08, cost(loss) 함수값 = 0.0006481,기울기 = [ 0.98821527] STEP = 09, cost(loss) 함수값 = 0.00018435,기울기 = [ 0.99371481] STEP = 10, cost(loss) 함수값 = 5.2437e-05,기울기 = [ 0.99664789] STEP = 11, cost(loss) 함수값 = 1.4916e-05,기울기 = [ 0.99821222] STEP = 12, cost(loss) 함수값 = 4.2428e-06,기울기 = [ 0.9990465] STEP = 13, cost(loss) 함수값 = 1.2069e-06,기울기 = [ 0.99949145] STEP = 14, cost(loss) 함수값 = 3.4317e-07,기울기 = [ 0.9997288] STEP = 15, cost(loss) 함수값 = 9.764e-08,기울기 = [ 0.99985534] STEP = 16, cost(loss) 함수값 = 2.7743e-08,기울기 = [ 0.99992287] STEP = 17, cost(loss) 함수값 = 7.9032e-09,기울기 = [ 0.99995887] STEP = 18, cost(loss) 함수값 = 2.2452e-09,기울기 = [ 0.99997807] STEP = 19, cost(loss) 함수값 = 6.3691e-10,기울기 = [ 0.99998832] STEP = 20, cost(loss) 함수값 = 1.8353e-10,기울기 = [ 0.99999374]
TensofFlow를 이용하여 cost(loss) 함수의 극소값 찾기
- 텐서플로우를 이용하면 cost(loss) 함수를 미분하지 않아도 된다.
- 다음과 같이 2줄로 코딩할 수 있다.
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.1) train = optimizer.minimize(cost)
\(W\)의 값을 초기에 5로 설정하고 위의 코드로 실행하는 코드
import tensorflow as tf X = [1, 2, 3] Y = [1, 2, 3] # W의 값을 5로 설정하고 학습 시킨다 W = tf.Variable(5.0) # 학습 모델의 가설 hypothesis = W * X # cost(loss) 함수 cost = tf.reduce_mean(tf.square(hypothesis - Y)) # 텐서플로우에서 제공하는 경사 하강법 메서드(이것이 매직이다!!!) optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.1) train = optimizer.minimize(cost) # 세션에서 그래프 초기화 sess = tf.Session() # 변수 초기화 sess.run(tf.global_variables_initializer()) for step in range(20): print(f"STEP = {step:03}, 기울기 = {sess.run(W):>.5}") sess.run(train)
초기값 5.0으로 실행한 결과
- 초기값 5.0으로 시작해서 빠르게 1로 수렴한다.
- 미분해서 구한 결과보다 더 정확하게 나온다.
STEP = 000, 기울기 = 5.0 STEP = 001, 기울기 = 1.2667 STEP = 002, 기울기 = 1.0178 STEP = 003, 기울기 = 1.0012 STEP = 004, 기울기 = 1.0001 STEP = 005, 기울기 = 1.0 STEP = 006, 기울기 = 1.0 STEP = 007, 기울기 = 1.0 STEP = 008, 기울기 = 1.0 STEP = 009, 기울기 = 1.0 STEP = 010, 기울기 = 1.0 STEP = 011, 기울기 = 1.0 STEP = 012, 기울기 = 1.0 STEP = 013, 기울기 = 1.0 STEP = 014, 기울기 = 1.0 STEP = 015, 기울기 = 1.0 STEP = 016, 기울기 = 1.0 STEP = 017, 기울기 = 1.0 STEP = 018, 기울기 = 1.0 STEP = 019, 기울기 = 1.0
초기값 -3.0으로 실행한 결과
STEP = 000, 기울기 = -3.0 STEP = 001, 기울기 = 0.73333 STEP = 002, 기울기 = 0.98222 STEP = 003, 기울기 = 0.99881 STEP = 004, 기울기 = 0.99992 STEP = 005, 기울기 = 0.99999 STEP = 006, 기울기 = 1.0 STEP = 007, 기울기 = 1.0 STEP = 008, 기울기 = 1.0 STEP = 009, 기울기 = 1.0 STEP = 010, 기울기 = 1.0 STEP = 011, 기울기 = 1.0 STEP = 012, 기울기 = 1.0 STEP = 013, 기울기 = 1.0 STEP = 014, 기울기 = 1.0 STEP = 015, 기울기 = 1.0 STEP = 016, 기울기 = 1.0 STEP = 017, 기울기 = 1.0 STEP = 018, 기울기 = 1.0 STEP = 019, 기울기 = 1.0
'모두를 위한 머신러닝' 카테고리의 다른 글
Lesson 3 연습 : Multi-variable Linear Regression (1) | 2017.04.16 |
---|---|
Lesson 3 : Multi-variable Linear Regression (0) | 2017.04.16 |
Lesson 2 : Linear Regression의 Hypothesis와 cost의 개념 (0) | 2017.04.10 |
Lesson 1 연습 : TensorFlow의 개념 (0) | 2017.04.03 |
Lesson 1 : 기계학습의 기본 개념 (3) | 2017.04.03 |