6주차 4월11일
빅데이터분석특강
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
import tensorflow.experimental.numpy as tnp
tnp.experimental_enable_numpy_behavior()
import graphviz
def gv(s): return graphviz.Source('digraph G{ rankdir="LR"'+s + '; }')
-
단순회귀분석의 예시
- $\hat{y}_i = \hat{\beta}_0 + \hat{\beta}_1 x_i, \quad i=1,2,\dots,n$
(표현1)
gv('''
"1" -> "β̂₀ + xₙ*β̂₁, bias=False"[label="* β̂₀"]
"xₙ" -> "β̂₀ + xₙ*β̂₁, bias=False"[label="* β̂₁"]
"β̂₀ + xₙ*β̂₁, bias=False" -> "ŷₙ"[label="identity"]
"." -> "...................................."[label="* β̂₀"]
".." -> "...................................."[label="* β̂₁"]
"...................................." -> "..."[label=" "]
"1 " -> "β̂₀ + x₂*β̂₁, bias=False"[label="* β̂₀"]
"x₂" -> "β̂₀ + x₂*β̂₁, bias=False"[label="* β̂₁"]
"β̂₀ + x₂*β̂₁, bias=False" -> "ŷ₂"[label="identity"]
"1 " -> "β̂₀ + x₁*β̂₁, bias=False"[label="* β̂₀"]
"x₁" -> "β̂₀ + x₁*β̂₁, bias=False"[label="* β̂₁"]
"β̂₀ + x₁*β̂₁, bias=False" -> "ŷ₁"[label="identity"]
''')
-
표현1의 소감?
- 교수님이 고생해서 만든것 같음
- 그런데 그냥 다 똑같은 그림의 반복이라 사실 고생한 의미가 없음.
(표현2)
-
그냥 아래와 같이 그리고 "모든 $i=1,2,3,\dots,n$에 대하여 $\hat{y}_i$을 아래의 그림과 같이 그린다"고 하면 될것 같다.
gv('''
"1" -> "β̂₀ + xᵢ*β̂₁, bias=False"[label="* β̂₀"]
"xᵢ" -> "β̂₀ + xᵢ*β̂₁, bias=False"[label="* β̂₁"]
"β̂₀ + xᵢ*β̂₁, bias=False" -> "ŷᵢ"[label="identity"]
''')
(표현3)
-
그런데 "모든 $i=1,2,3,\dots,n$에 대하여 $\hat{y}_i$을 아래의 그림과 같이 그린다" 라는 언급자체도 반복할 필요가 없을 것 같다. (어차피 당연히 그럴테니까) 그래서 단순히 아래와 같이 그려도 무방할듯 하다.
gv('''
"1" -> "β̂₀ + x*β̂₁, bias=False"[label="* β̂₀"]
"x" -> "β̂₀ + x*β̂₁, bias=False"[label="* β̂₁"]
"β̂₀ + x*β̂₁, bias=False" -> "ŷ"[label="identity"]
''')
(표현4)
-
위의 모델은 아래와 같이 쓸 수 있다. ($\beta_0$를 바이어스로 표현)
gv('''
"x" -> "x*β̂₁, bias=True"[label="*β̂₁"] ;
"x*β̂₁, bias=True" -> "ŷ"[label="indentity"] ''')
- 실제로는 이 표현을 많이 사용함
(표현5)
-
벡터버전으로 표현하면 아래와 같다. 이 경우에는 ${\bf X}=[1,x]$에 포함된 1이 bias의 역할을 해주므로 bias = False
임.
gv('''
"X" -> "X@β̂, bias=False"[label="@β̂"] ;
"X@β̂, bias=False" -> "ŷ"[label="indentity"] ''')
- 저는 이걸 좋아해요
(표현5)'
-
딥러닝에서는 $\hat{\boldsymbol{\beta}}$ 대신에 $\hat$을 라고 표현한다.
gv('''
"X" -> "X@Ŵ, bias=False"[label="@Ŵ"] ;
"X@Ŵ, bias=False" -> "ŷ"[label="identity"] ''')
-
실제로는 표현4 혹은 표현5를 외우면 된다.
-
(표현4) 혹은 (표현5)의 그림은 레이어로 설명할 수 있다.
-
레이어는 항상 아래와 같은 규칙을 가진다.
- 첫 동그라미는 레이어의 입력이다.
- 첫번째 화살표는 선형변환을 의미한다.
- 두번째 동그라미는 선형변환의 결과이다. (이때 bias가 false인지 true인지에 따라서 실제 수식이 조금 다름)
- 두번째 화살표는 두번째 동그라미에 어떠한 함수 $f$를 취하는 과정을 의미한다. (우리의 그림에서는 $f(x)=x$)
- 세번째 동그라미는 레이어의 최종출력이다.
-
엄청 복잡한데, 결국 레이어를 만들때 위의 그림들을 의미하도록 하려면 아래의 4개의 요소만 필요하다.
- 레이어의 입력차원
- 선형변환의 결과로 얻어지는 차원
- 선형변환에서 바이어스를 쓸지? 안쓸지?
- 함수 $f$
-
주목: 1,2가 결정되면 자동으로 $\hat$의 차원이 결정된다.
(예시)
- 레이어의 입력차원=2, 선형변환의 결과로 얻어지는 차원=1: $\hat{\bf W}$는 (2,1) 매트릭스
- 레이어의 입력차원=20, 선형변환의 결과로 얻어지는 차원=5: $\hat{\bf W}$는 (20,5) 매트릭스
- 레이어의 입력차원=2, 선형변환의 결과로 얻어지는 차원=50: $\hat{\bf W}$는 (2,50) 매트릭스
-
주목2: 이중에서 절대 생략불가능 것은 "2. 선형변환의 결과로 얻어지는 차원" 이다.
- 레이어의 입력차원: 실제 레이어에 데이터가 들어올 때 데이터의 입력차원을 컴퓨터 스스로 체크하여 $\hat{\bf W}$의 차원을 결정할 수 있음.
- 바이어스를 쓸지? 안쓸지? 기본적으로 쓴다고 가정한다.
- 함수 $f$: 기본적으로 항등함수를 가정하면 된다.
-
기본뼈대: net생성 $\to$ add(layer) $\to$ compile(opt,loss) $\to$ fit(data,epochs)
-
데이터정리
tnp.random.seed(43052)
N= 200
x= tnp.linspace(0,1,N)
epsilon= tnp.random.randn(N)*0.5
y= 2.5+4*x +epsilon
X=tf.stack([tf.ones(N,dtype='float64'),x],axis=1)
(0단계) 데이터정리
y=y.reshape(N,1)
x=x.reshape(N,1)
x.shape,y.shape
(1단계) net 생성
net = tf.keras.Sequential()
(2단계) net.add(layer)
layer = tf.keras.layers.Dense(1)
net.add(layer)
(3단계) net.compile(opt,loss_fn)
net.compile(tf.keras.optimizers.SGD(0.1), tf.keras.losses.MSE)
(4단계) net.fit(x,y,epochs)
net.fit(x,y,epochs=1000,verbose=0,batch_size=N) # batch_size=N 일 경우에 경사하강법이 적용, batch_size!=N 이면 확률적 경사하강법 적용
(결과확인)
net.weights
(0단계) 데이터정리
X.shape,y.shape
(1단계) net 생성
net = tf.keras.Sequential()
(2단계) net.add(layer)
layer = tf.keras.layers.Dense(1,use_bias=False)
net.add(layer)
(3단계) net.compile(opt,loss_fn)
net.compile(tf.keras.optimizers.SGD(0.1), tf.keras.losses.MSE)
(4단계) net.fit(x,y,epochs)
net.fit(X,y,epochs=1000,verbose=0,batch_size=N) # batch_size=N 일 경우에 경사하강법이 적용, batch_size!=N 이면 확률적 경사하강법 적용
(결과확인)
net.weights
-
잠깐 Dense layer를 만드는 코드를 정리해보자.
(1) 아래는 모두 같은 코드이다.
- tf.keras.layers.Dense(1)
- tf.keras.layers.Dense(units=1)
- tf.keras.layers.Dense(units=1,activation='linear') // identity 가 더 맞는것 같은데..
- tf.keras.layers.Dense(units=1,activation='linear',use_bias=True)
(2) 아래의 코드1,2는 (1)의 코드들과 살짝 다른코드이다. (코드1과 코드2는 같은코드임)
- tf.keras.layers.Dense(1,input_dim=2) # 코드1
- tf.keras.layers.Dense(1,input_shape=(2,)) # 코드2
(3) 아래는 사용불가능한 코드이다.
- tf.keras.layers.Dense(1,input_dim=(2,)) # 코드1
- tf.keras.layers.Dense(1,input_shape=2) # 코드2
-
왜 input_dim이 필요한가?
net1 = tf.keras.Sequential()
net1.add(tf.keras.layers.Dense(1,use_bias=False))
net2 = tf.keras.Sequential()
net2.add(tf.keras.layers.Dense(1,use_bias=False,input_dim=2))
net1.weights
net2.weights
net1.summary()
net2.summary()
(0단계) 데이터정리
y=y.reshape(N,1)
x=x.reshape(N,1)
x.shape,y.shape
(1단계) net생성
net = tf.keras.Sequential()
(2단계) net.add(layer)
layer = tf.keras.layers.Dense(1,input_dim=1)
net.add(layer)
초기값을 설정
net.weights
net.get_weights()
- weight, bias순으로 출력
net.set_weights?
- layer_b.set_weights(layer_a.get_weights()) 와 같은방식으로 쓴다는 것이군?
-
한번따라해보자.
_w = net.get_weights()
_w
- 길이가 2인 리스트이고, 각 원소는 numpy array 임
net.set_weights(
[np.array([[10.0]],dtype=np.float32), # weight, β1_hat
np.array([-5.0],dtype=np.float32)] # bias, β0_hat
)
net.weights
(3단계) net.compile()
net.compile(tf.keras.optimizers.SGD(0.1),tf.losses.MSE)
(4단계) net.fit()
net.fit(x,y,epochs=1000,verbose=0,batch_size=N)
결과확인
net.weights
(0단계) 데이터정리
X.shape, y.shape
(1단계) net생성
net = tf.keras.Sequential()
(2단계) net.add(layer)
layer = tf.keras.layers.Dense(1,use_bias=False,input_dim=2)
net.add(layer)
초기값을 설정하자
net.set_weights([np.array([[ -5.0],[10.0]], dtype=np.float32)])
net.get_weights()
(3단계) net.compile()
net.compile(tf.keras.optimizers.SGD(0.1), tf.losses.MSE)
(4단계) net.fit()
net.fit(X,y,epochs=1000,verbose=0,batch_size=N)
net.weights
-
사실 실전에서는 초기값을 설정할 필요가 별로 없음.
(0단계) 데이터정리
X.shape, y.shape
(1단계) net생성
net = tf.keras.Sequential()
(2단계) net.add(layer)
layer = tf.keras.layers.Dense(1,use_bias=False)
net.add(layer)
(3단계) net.compile()
loss_fn = lambda y,yhat: (y-yhat).T @ (y-yhat) / N
net.compile(tf.keras.optimizers.SGD(0.1), loss_fn)
(4단계) net.fit()
net.fit(X,y,epochs=1000,verbose=0,batch_size=N)
net.weights
(0단계) 데이터정리
X.shape, y.shape
(1단계) net생성
net = tf.keras.Sequential()
(2단계) net.add(layer)
net.add(tf.keras.layers.Dense(1,use_bias=False))
(3단계) net.compile()
net.compile(tf.keras.optimizers.SGD(0.1), loss='mse')
(4단계) net.fit()
net.fit(X,y,epochs=1000,verbose=0,batch_size=N)
net.weights
(0단계) 데이터정리
X.shape, y.shape
(1단계) net생성
net = tf.keras.Sequential()
(2단계) net.add(layer)
net.add(tf.keras.layers.Dense(1,use_bias=False))
(3단계) net.compile()
net.compile(optimizer='sgd', loss='mse')
#net.optimizer.lr = tf.Variable(0.1,dtype=tf.float32)
#net.optimizer.lr = 0.1
(4단계) net.fit()
net.fit(X,y,epochs=5000,verbose=0,batch_size=N)
net.weights
model: $y_i \approx \beta_0 +\beta_1 x_i$
np.random.seed(43052)
N= 100
x= np.random.randn(N)
epsilon = np.random.randn(N)*0.5
y= 2.5+4*x +epsilon
X= np.stack([np.ones(N),x],axis=1)
y= y.reshape(N,1)
plt.plot(x,y,'o') # 관측한 자료
beta_hat = np.array([-3,-2]).reshape(2,1)
yhat = X@beta_hat
plt.plot(x,y,'o')
plt.plot(x,yhat.reshape(-1),'-')
더 좋은 적합선을 얻기위해서!
slope = (2*X.T@X@beta_hat - 2*X.T@y)/ N
beta_hat2 = beta_hat - 0.1*slope
yhat2 = X@beta_hat2
plt.plot(x,y,'o')
plt.plot(x,yhat.reshape(-1),'-')
plt.plot(x,yhat2.reshape(-1),'-')
초록색이 좀 더 나아보인다.
beta_hat = np.array([-3,-2]).reshape(2,1)
beta_hats = beta_hat # beta_hats = beta_hat.copy() 가 더 안전한 코드입니다.
for i in range(1,30):
yhat = X@beta_hat
slope = (2*X.T@X@beta_hat - 2*X.T@y) / N
beta_hat = beta_hat - 1.0*slope # 0.1은 적당, 0.3은 쪼금빠르지만 그래도 적당, 0.9는 너무 나간것같음, 1.0 은 수렴안함, 1.2
beta_hats = np.concatenate([beta_hats,beta_hat],axis=1)
beta_hats
b0hats = beta_hats[0].tolist()
b1hats = beta_hats[1].tolist()
np.linalg.inv(X.T@X) @ X.T @ y
from matplotlib import animation
plt.rcParams["animation.html"] = "jshtml"
fig = plt.figure(); fig.set_figheight(5); fig.set_figwidth(12)
ax1= fig.add_subplot(1,2,1)
ax2= fig.add_subplot(1,2,2,projection='3d')
# ax1: 왼쪽그림
ax1.plot(x,y,'o')
line, = ax1.plot(x,b0hats[0] + b1hats[0]*x)
# ax2: 오른쪽그림
β0,β1 = np.meshgrid(np.arange(-6,11,0.25),np.arange(-6,11,0.25),indexing='ij')
β0=β0.reshape(-1)
β1=β1.reshape(-1)
loss_fn = lambda b0,b1: np.sum((y-b0-b1*x)**2)
loss = list(map(loss_fn, β0,β1))
ax2.scatter(β0,β1,loss,alpha=0.02)
ax2.scatter(2.5451404,3.94818596,loss_fn(2.5451404,3.94818596),s=200,marker='*')
def animate(i):
line.set_ydata(b0hats[i] + b1hats[i]*x)
ax2.scatter(b0hats[i],b1hats[i],loss_fn(b0hats[i],b1hats[i]),color="grey")
ani = animation.FuncAnimation(fig,animate,frames=30)
ani
model: $y_i \approx \beta_0 +\beta_1 e^{-x_i}$
np.random.seed(43052)
N= 100
x= np.linspace(-1,1,N)
epsilon = np.random.randn(N)*0.5
y= 2.5+4*np.exp(-x) +epsilon
plt.plot(x,y,'o')
X= np.stack([np.ones(N),np.exp(-x)],axis=1)
y= y.reshape(N,1)
beta_hat = np.array([-3,-2]).reshape(2,1)
beta_hats = beta_hat.copy() # shallow copy, deep copy <--- 여름 방학 특강
for i in range(1,30):
yhat = X@beta_hat
slope = (2*X.T@X@beta_hat - 2*X.T@y) /N
beta_hat = beta_hat - 0.05*slope
beta_hats = np.concatenate([beta_hats,beta_hat],axis=1)
beta_hats
b0hats= beta_hats[0].tolist()
b1hats= beta_hats[1].tolist()
np.linalg.inv(X.T@X)@X.T@y
fig = plt.figure(); fig.set_figheight(5); fig.set_figwidth(12)
ax1= fig.add_subplot(1,2,1)
ax2= fig.add_subplot(1,2,2,projection='3d')
# ax1: 왼쪽그림
ax1.plot(x,y,'o')
line, = ax1.plot(x,b0hats[0] + b1hats[0]*np.exp(-x))
# ax2: 오른쪽그림
β0,β1 = np.meshgrid(np.arange(-6,11,0.25),np.arange(-6,11,0.25),indexing='ij')
β0=β0.reshape(-1)
β1=β1.reshape(-1)
loss_fn = lambda b0,b1: np.sum((y-b0-b1*np.exp(-x))**2)
loss = list(map(loss_fn, β0,β1))
ax2.scatter(β0,β1,loss,alpha=0.02)
ax2.scatter(2.46307644,3.99681332,loss_fn(2.46307644,3.99681332),s=200,marker='*')
def animate(i):
line.set_ydata(b0hats[i] + b1hats[i]*np.exp(-x))
ax2.scatter(b0hats[i],b1hats[i],loss_fn(b0hats[i],b1hats[i]),color="grey")
ani = animation.FuncAnimation(fig,animate,frames=30)
ani
model: $y_i \approx \beta_0 +\beta_1 e^{-x_i} + \beta_2 \cos(5x_i)$
np.random.seed(43052)
N= 100
x= np.linspace(-1,1,N)
epsilon = np.random.randn(N)*0.5
y= 2.5+4*np.exp(-x) + 5*np.cos(5*x) + epsilon
plt.plot(x,y,'o')
X=np.stack([np.ones(N),np.exp(-x),np.cos(5*x)],axis=1)
y=y.reshape(N,1)
beta_hat = np.array([-3,-2,-1]).reshape(3,1)
beta_hats = beta_hat.copy()
for i in range(1,30):
yhat = X@beta_hat
slope = (2*X.T@X@beta_hat -2*X.T@y) /N
beta_hat = beta_hat - 0.1 * slope
beta_hats= np.concatenate([beta_hats,beta_hat],axis=1)
beta_hats
b0hats,b1hats,b2hats = beta_hats
np.linalg.inv(X.T@X) @ X.T @ y
fig = plt.figure(); fig.set_figheight(5); fig.set_figwidth(12)
ax1= fig.add_subplot(1,2,1)
ax2= fig.add_subplot(1,2,2,projection='3d')
# ax1: 왼쪽그림
ax1.plot(x,y,'o')
line, = ax1.plot(x,b0hats[0] + b1hats[0]*np.exp(-x) + b2hats[0]*np.cos(5*x))
# ax2: 오른쪽그림
# β0,β1 = np.meshgrid(np.arange(-6,11,0.25),np.arange(-6,11,0.25),indexing='ij')
# β0=β0.reshape(-1)
# β1=β1.reshape(-1)
# loss_fn = lambda b0,b1: np.sum((y-b0-b1*np.exp(-x))**2)
# loss = list(map(loss_fn, β0,β1))
# ax2.scatter(β0,β1,loss,alpha=0.02)
# ax2.scatter(2.46307644,3.99681332,loss_fn(2.46307644,3.99681332),s=200,marker='*')
def animate(i):
line.set_ydata(b0hats[i] + b1hats[i]*np.exp(-x) + b2hats[i]*np.cos(5*x))
# ax2.scatter(b0hats[i],b1hats[i],loss_fn(b0hats[i],b1hats[i]),color="grey")
ani = animation.FuncAnimation(fig,animate,frames=30)
ani
model: $y_i \approx \beta_0 +\beta_1 e^{-x_i} + \beta_2 \cos(5x_i)$
np.random.seed(43052)
N= 100
x= np.linspace(-1,1,N)
epsilon = np.random.randn(N)*0.5
y= 2.5+4*np.exp(-x) + 5*np.cos(5*x) + epsilon
X=np.stack([np.ones(N),np.exp(-x),np.cos(5*x)],axis=1)
y=y.reshape(N,1)
net = tf.keras.Sequential() # 1: 네트워크 생성
net.add(tf.keras.layers.Dense(1,use_bias=False)) # 2: add layer
net.compile(tf.optimizers.SGD(0.1), loss='mse') # 3: compile
net.fit(X,y,epochs=30, batch_size=N) # 4: fit
net.weights
plt.plot(x,y,'o')
plt.plot(x,(X@net.weights).reshape(-1),'--')
model: $y_i \approx \beta_0 +\beta_1 e^{-x_i}$
np.random.seed(43052)
N= 100
x= np.linspace(-1,1,N)
epsilon = np.random.randn(N)*0.5
y= 2.5+4*np.exp(-x) +epsilon
X = np.stack([np.ones(N),np.exp(-x)],axis=1)
y = y.reshape(N,1)
net = tf.keras.Sequential() # 1: 네트워크 생성
net.add(tf.keras.layers.Dense(1,use_bias=False)) # 2: add layer
net.compile(tf.optimizers.SGD(0.1), loss='mse') # 3: compile
net.fit(X,y,epochs=30, batch_size=N) # 4: fit