4주차-3월 28일
빅데이터분석특강
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import tensorflow.experimental.numpy as tnp
tnp.experimental_enable_numpy_behavior()
x = tnp.array([20.1, 22.2, 22.7, 23.3, 24.4, 25.1, 26.2, 27.3, 28.4, 30.4])
tf.random.set_seed(43052)
epsilon=tf.random.normal([10])
y=10.2 + 2.2*x + epsilon
y
beta0 = tf.Variable(9.0)
beta1 = tf.Variable(2.0)
with tf.GradientTape(persistent=True) as tape:
loss = sum((y-beta0-beta1*x)**2)
tape.gradient(loss, beta0), tape.gradient(loss, beta1)
- 예제10:카페예제의 매트릭스 버전
X = tnp.array([1]*10 +[20.1, 22.2, 22.7, 23.3, 24.4, 25.1, 26.2, 27.3, 28.4, 30.4]).reshape(2,10).T
X
beta = tnp.array([9.0,2.0]).reshape(2,1)
beta
X@beta
beta_true = tnp.array([10.2,2.2]).reshape(2,1)
y = X@beta_true+epsilon.reshape(10,1)
y
with tf.GradientTape(persistent=True) as tape:
tape.watch(beta)
yhat= X@beta
loss= (y-yhat).T @(y-yhat)
tape.gradient(loss,beta)
- 이론적인 값을 확인하면
-2*X.T @ y + 2*X.T@X@beta
- 예제11 : 위의 예제에서 이론적인 $\beta$의 최적값을 찾아보고 (즉 $\hat\beta$을 찾고) 그 지점에서 loss의 미분값(=접선의 기울기)를 구하라. 결과가 0인지 확인하라. (단 0은 길이가 2이고 각 원소가 0인 벡터)
$\beta$의 최적값은 $(X'X)^{-1}X'y$이다.
beta_optimal = tf.linalg.inv(X.T @ X) @ X.T @y
with tf.GradientTape(persistent=True) as tape:
tape.watch(beta_optimal)
yhat= X@beta_optimal
loss= (y-yhat).T @(y-yhat)
tape.gradient(loss,beta_optimal)
-
beta_true에서의 기울기도 계산해보자.
with tf.GradientTape(persistent=True) as tape:
tape.watch(beta_true)
yhat= X@beta_true
loss= (y-yhat).T @(y-yhat)
tape.gradient(loss,beta_true)
- 샘플사이즈가 커진다면
tape.gradient(loss,beta_true)
$\approx$tape.gradient(loss,beta_optimal)
- 샘플사이즈가 커진다면
beta_true
$\approx$beta_optimal
(1) beta = [-10.00,-9.99,...,10.00] 와 같은 리스트를 만든다.
(2) (1)의 리스트의 각원소에 해당하는 loss를 구한다.
(3) (2)에서 구한 loss를 제일 작게 만드는 beta를 찾는다.
beta = np.linspace(-10,10,100)
loss = (beta/2-1)**2
tnp.argmin([1,2,-3,3,4])
tnp.argmin([1,2,3,-3,4])
tnp.argmin(loss)
beta[59]
(beta[60]/2-1)**2
(1) beta = -5로 셋팅한다. (초깃값으로 셋팅)
(-5/2-1)**2
(2) beta= -5 근처에서 조금씩 이동하여 loss를 조사해본다.
(-4.99/2-1)**2 ## 오른쪽으로 0.01 이동하고 loss조사 (미분)
(-5.01/2-1)**2 ## 왼쪽으로 0.01 이동하고 loss조사 (미분)
(3) (2)의 결과를 잘 해석하고 더 유리한 쪽으로 이동 (미분 결과 관찰 후 유리한 쪽으로 이동)
(4) 위의 과정을 반복하고 왼쪽, 오른쪽 어느쪽으로 움직여도 이득이 없다면 멈춘다.
-
(2)-(3)의 과정은 beta=-5 에서 미분계수를 구하고 미분계수가 양수이면 왼쪽으로 움직이고 음수면 오른쪽으로 움직인다
고 해석가능. 아래그림을 보면 더 잘 이해가 된다.
plt.plot(beta,loss)
-
그렇다면
$\beta_{new} = \begin{cases} \beta_{old} + 0.01, & loss'(\beta_{old})<0 \\ \beta_{old} - 0.01, & loss'(\beta_{old})>0 \end{cases} $
plt.plot(beta,loss)
-
$\beta= -10$일 경우의 접선의 기울기? $\beta=-4$일때 접선의 기울기?
- $\beta=-10$ => 기울기는 -6
- $\beta=-4$ => 기울기는 -3
-
실제로 6,3씩 이동할수는 없으니 적당한 $\alpha(예를 들면 \alpha = 0.01)$를 잡아서 곱한만큼 이동하자.
-
수식화하면
- $\beta_{new} = \beta_{old} - \alpha~ loss'(\beta_{old})$
- $\beta_{new} = \beta_{old} - \alpha~ \left[\frac{\partial}{\partial \beta}loss(\beta)\right]_{\beta=\beta_{old}}$
-
$\alpha$의 의미
- $\alpha$가 크면 크게크게 움직이고 작으면 작게작게 움직인다.
- $\alpha>0$ 이어야 한다.
-
iter 1
-
$\beta=-10$이라고 하자.
beta = tf.Variable(-10.0)
with tf.GradientTape(persistent=True) as tape:
loss = (beta/2-1)**2
tape.gradient(loss,beta)
$\beta = -10$에서 0.01만큼 움직이고 싶다.
alpha = 0.01/6
alpha * tape.gradient(loss,beta)
beta.assign_sub(alpha * tape.gradient(loss,beta))
beta
-
iter 2
with tf.GradientTape(persistent=True) as tape:
loss = (beta/2-1)**2
beta.assign_sub(tape.gradient(loss,beta)*alpha)
-
for 문을 이용하자.
(강의용)
beta = tf.Variable(-10.0)
for k in range(10000):
with tf.GradientTape(persistent=True) as tape:
loss = (beta/2-1)**2
beta.assign_sub(tape.gradient(loss,beta)*alpha)
beta
(시도 1)
beta = tf.Variable(-10.0)
for k in range(100):
with tf.GradientTape(persistent=True) as tape:
loss = (beta/2-1)**2
beta.assign_sub(tape.gradient(loss,beta)*alpha)
beta
(시도 2)
beta = tf.Variable(-10.0)
for k in range(1000):
with tf.GradientTape(persistent=True) as tape:
loss = (beta/2-1)**2
beta.assign_sub(tape.gradient(loss,beta)*alpha)
beta
-
너무 느린 것 같다? $\to$ $\alpha$를 키워보자!
-
목표 : $\alpha$에 따라서 수렴과정이 어떻게 달라지는지 시각화해보자.
[시각화 코드 예비학습]
fig = plt.figure() # 도화지가 만들어지고 fig라는 이름을 붙인다.
fig
ax = fig.add_subplot() #fig는 ax라는 물체를 만든다.
id(fig.axes[0])
id(ax)
pnts, = ax.plot([1,2,3],[4,5,6],'or')
pnts
pnts.get_xdata()
pnts.get_ydata()
fig
pnts.set_ydata([5,5,5])
pnts.get_ydata()
fig
-
응용
plt.rcParams["animation.html"] = "jshtml"
from matplotlib import animation
def animate(i):
if i%2 == 0:
pnts.set_ydata([4,5,6])
else:
pnts.set_ydata([5,5,5])
ani=animation.FuncAnimation(fig,animate,frames=10)
ani
예비학습 끝!
-
beta_lst = [-10,-9,-8] 로 이동한다고 하자.
beta_lst = [-10,-9,-8]
loss_lst = [(-10/2-1)**2, (-9/2-1)**2, (-8/2-1)**2]
fig = plt.figure()
ax = fig.add_subplot()
_beta = np.linspace(-15,19,100)
ax.plot(_beta,(_beta/2-1)**2)
fig
pnts, = ax.plot(beta_lst[0],loss_lst[0],'ro')
fig
def animate(i):
pnts.set_xdata(beta_lst[:(i+1)])
pnts.set_ydata(loss_lst[:(i+1)])
ani = animation.FuncAnimation(fig, animate, frames=3)
ani
-
최종아웃풋
beta = tf.Variable(-10.0)
alpha = 0.01/6
beta_lst = []
loss_lst = []
beta_lst.append(beta.numpy())
loss_lst.append((beta.numpy()/2-1)**2)
with tf.GradientTape(persistent=True) as tape:
tape.watch(beta)
loss = (beta/2-1)**2
beta.assign_sub(tape.gradient(loss,beta)*alpha)
beta_lst.append(beta.numpy())
loss_lst.append((beta.numpy()/2-1)**2)
beta_lst, loss_lst
-
for
beta = tf.Variable(-10.0)
alpha = 0.01/6
beta_lst = []
loss_lst = []
beta_lst.append(beta.numpy())
loss_lst.append((beta.numpy()/2-1)**2)
for k in range(100):
with tf.GradientTape(persistent=True) as tape:
tape.watch(beta)
loss = (beta/2-1)**2
beta.assign_sub(tape.gradient(loss,beta)*alpha)
beta_lst.append(beta.numpy())
loss_lst.append((beta.numpy()/2-1)**2)
fig = plt.figure()
ax = fig.add_subplot()
ax.plot(_beta,(_beta/2-1)**2)
pnts,= ax.plot(beta_lst[0],loss_lst[0],'or')
ani = animation.FuncAnimation(fig,animate,frames=100)
ani
beta = tf.Variable(-3.0)
alpha = 0.01/3
beta_lst=[]
loss_lst=[]
beta_lst.append(beta.numpy())
loss_lst.append((beta.numpy()-1)**2)
for k in range(100):
with tf.GradientTape(persistent=True) as tape:
tape.watch(beta)
loss = (beta-1)**2
beta.assign_sub(tape.gradient(loss, beta)*alpha)
beta_lst.append(beta.numpy())
loss_lst.append((beta.numpy()-1)**2)
_beta = np.linspace(-20,22,100)
fig = plt.figure()
ax = fig.add_subplot()
ax.plot(_beta,(_beta-1)**2)
pnts, = ax.plot(beta_lst[0],loss_lst[0],'or')
def animate(i):
pnts.set_xdata(beta_lst[:(i+1)])
pnts.set_ydata(loss_lst[:(i+1)])
ani = animation.FuncAnimation(fig, animate, frames=100)
ani