빅데이터 분석 특강 (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.
$f(x) = x$ 로 표현이 되는 것을
$f(\hat{\beta}_0 + x_1 \hat{\beta}) = \hat{y}_1$ 이렇게 항등함수를 취해서 구해준다.
그러면 $\hat{\beta}_0 + x_1 \hat{\beta} = \hat{y}_1$ 이게 되겠지?
2.
..
n.
..
-
표현1의 소감?
- 그저 고생해서 만든것 같음
- 그런데 그냥 다 똑같은 그림의 반복이라 사실 고생한 의미가 없음.
- $\hat{y}$를 만드는 rule이 바뀌지 않기 때문, 모든 observation에 똑같이 적용
- 그 rule이 다르다면 반복하면 안 되겠지.(여기서 rule은 식을 의미)
(표현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$를 바이어스로 표현)
- $x \hat{\beta}_1 + \hat{\beta}_0$
- input $\times$ parameter + bias
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"] ''')
- 교수님 선호 표현
$\begin{bmatrix} 1 & X_1 \end{bmatrix} \begin{bmatrix} \hat{\beta}_0 \\ \hat{\beta}_1 \end{bmatrix} \rightarrow$ vector version & bias $\rightarrow\hat{\beta}_0 + x_1 \hat{\beta}_1 + \hat{\alpha}$
- 기본적으로 직선으로 보겠다는 뜻.
- $\hat{y}_1 = \hat{\beta}-0 + x_1 \hat{\beta}_1$
- $\hat{y}_1 = \hat{\alpha}_0 + \hat{\beta}_0 + x_1 \hat{\beta}_1$ 이렇게 표현한다면? 굳이 bias를 두 개의 변수나 쓸 필요가 있을까? 싶은거지.
(표현5)`
-
딥러닝에서는 $\hat{\boldsymbol{\beta}}$ 대신에 $\hat$을 라고 표현한다.
- $\bf{W}$는 weight를 의미하지~
- $\hat{y}_i = \hat{w}_0 + x\hat{w}_1$
gv('''
"X" -> "X@Ŵ, bias=False"[label="@Ŵ"] ;
"X@Ŵ, bias=False" -> "ŷ"[label="identity"] ''')
-
실제로는 표현4 혹은 표현5를 외우면 된다.
-
(표현4) 혹은 (표현5)의 그림은 레이어로 설명할 수 있다.
glm 추상화...?
-
레이어는 항상 아래와 같은 규칙을 가진다.
- 첫 동그라미는 레이어의 입력이다.
- 첫번째 화살표는 선형변환을 의미한다.
- 두번째 동그라미는 선형변환의 결과이다. (이때 bias가 false인지 true인지에 따라서 실제 수식이 조금 다름)
- 두번째 화살표는 두번째 동그라미에 어떠한 함수 $f$를 취하는 과정을 의미한다. (우리의 그림에서는 항등함수 취하니까 $f(x)=x$)
- 세번째 동그라미는 레이어의 최종출력이다.
-
엄청 복잡한데, 결국 레이어를 만들때 위의 그림들을 의미하도록 하려면 아래의 4개의 요소만 필요하다.
- 레이어의 입력차원
- 선형변환의 결과로 얻어지는 차원
- 선형변환에서 바이어스를 쓸지? 안쓸지?
- 함수 $f$
-
$\star$주목: 1,2가 결정되면 자동으로 $\hat$의 차원이 결정된다.
(예시)
- 레이어의 입력차원($p$)=2, 선형변환의 결과로 얻어지는 차원=1: $\hat{\bf W}$는 (2,1) 매트릭스
- $(n,p) \times \bf{W} = (n,1) \rightarrow (1,2) \times (2,1) = (1,1)$
- 레이어의 입력차원($p$)=20, 선형변환의 결과로 얻어지는 차원=5: $\hat{\bf W}$는 (20,5) 매트릭스
- $(n,p) \times \bf{W} = (n,1) \rightarrow (1,20) \times (20,5) = (1,5)$
- 레이어의 입력차원($p$)=2, 선형변환의 결과로 얻어지는 차원=50: $\hat{\bf W}$는 (2,50) 매트릭스
- $(n,p) \times \bf{W} = (n,1) \rightarrow (1,2) \times (2,50) = (1,50)$
-
$\star$주목2: 이중에서 절대 생략불가능 것은 "2. 선형변환의 결과로 얻어지는 차원" 이다. (1,3,4는 생략가능)
- 1 레이어의 입력차원 생략? $\rightarrow$ 레이어의 입력차원: 실제 레이어에 데이터가 들어올 때 데이터의 입력차원을 컴퓨터 스스로 체크하여 $\hat{\bf W}$의 차원을 결정할 수 있음.
- ex) 선형변환의 결과로 얻어지는 차원이 5인 걸 아는데 입력차원이 10이야? 그럼 $\hat{\bf{W}}$를 $(10,5)$로 매트릭스 맞추면 되지.
- 사용자에게 가장 편리함을 가져다 준 조건(?)..
- 3 선형변환에서 바이어스를 쓸지? 안쓸지? 생략? $\rightarrow$ 바이어스를 쓸지? 안쓸지? 기본적으로 쓴다고 가정한다.
- 4 함수 $𝑓$ 생략? $\rightarrow$ 함수 $f$: 기본적으로 항등함수를 가정하면 된다.
-
기본뼈대: net생성 $\to$ add(layer) $\to$ compile(opt,loss) $\to$ fit(data,epochs)
- loss function을 정의하고 그 loss function을 minimize하는 반복 알고리즘을 결정하여 학습한다.
-
데이터정리
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(-1)
x = x.reshape(-1)
스칼라니까 이전에 배웠듯이 이렇게 해야하지 않아?
차원 에러가 뜬다.
길이가 200인 벡터가 아니라 (200,1)인 벡터로 만들어줘야 한다.
y=y.reshape(N,1)
x=x.reshape(N,1)
x.shape,y.shape
(1단계) net 생성
net = tf.keras.Sequential()
(2단계) net.add(layer)
-
tf.keras.layers.Dense(1)
여기서 1이란, 선형결과로 얻어지는 차원을 의미함, 1차원 - 입력차원? 데이터를 넣어보고 결정, 바이어스=디폴드값을 쓰겠음
(use_bias=true)
, 함수도 디폴트값을 쓰겠음 $(f(x)=x)$
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)
- batch_size=N 일 경우에 경사하강법이 적용, batch_size!=N 이면 확률적 경사하강법 적용
- 우리가 구현한 것과 같은 결과를 얻기 위해서 batch_size를 200으로 설정
🤓 질문!
- 확률적 경사하강법 -
batch_size!=N
N 개 중 batch_size 만큼만- 샘플 데이터에 대해서만 경사gradient 계산
- 최적해에 정확히 도닳하지 못할 가능성
- 확률적 경사 하강법은 속도가 매우 빠르고 메모리를 적게 먹는다는 장점이 있으나, 경사를 구할 때, 무작위성을 띄므로 지역 최솟값에서 탈출하기 쉬우나, 전역 최솟값에 다다르기 힘들다는 단점 -> 미니 배치 경사 하강법 등장.
- 경사하강법 -
batch_size=N
N 개 중 N개 모두- 경사하강법 대상이 배치 크기와 동일
- 안정적으로 수혐하나 이 때문에 최소해local minimum에 빠지더라도 헤어나오기 힘들다. 즉 local optima 문제가 발생할 가능성이 높다.
- 학습 데이터셋이 커질수록 시간과 리소스 소모가 지나치게 크다.
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)
vector 구할 때 bias는 false로, 굳이 bias 나누지 말고 합치자
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
net = tf.keras.Sequential()
layer = tf.keras.layers.Dense(1)
net.add(layer)
net.compile(tf.keras.optimizers.SGD(0.1), tf.keras.losses.MSE)
net.fit(X,y,epochs=1000,verbose=0,batch_size=N)
net.weights
이것은 실수!
- $\bf{y} \approx 2.5 + 4 \times x$ 우리가 결과적 얻을 모형
- 하지만 $\hat{\beta}_1$은 한 개 해놓고, 2.5 부분은 $\hat{\alpha}_0 + \hat{\beta}_0 \approx $대략 $ 2.5 =1.818664+0.7650072$ 이렇게 해주면 어떡해~
tf.keras.layers.Dense?
-
잠깐 Dense layer를 만드는 코드를 정리해보자.
(1) 아래는 모두 같은 코드이다.
- tf.keras.layers.Dense(1)
- tf.keras.layers.Dense(units=1) , 선형결과로 얻어지는 차원
-
tf.keras.layers.Dense(units=1,activation='linear') // identity 가 더 맞는것 같은데.. 교수님's opinion...
- activation: Activation function to use.
- If you don't specify anything, no activation is applied
- (ie. "linear" activation:
a(x) = x
). -> 아무것도 지정 안 하면 항등함수로 지정된다.
- 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
안 나오는 이유: 모르니까..
- 입력차원input_dim 혹은 input_shape 지정 안 해주면 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)
출력은 1 입력은 1 bia는 true(기본 옵션, 안 건들어)
net.add(layer)
초기값을 설정
net.weights
net.get_weights()
- weight, bias순으로 출력 (바로 위의 결과도 마찬가지 array([[1.2078832]] - weight, array([0.] - bias)
net.set_weights?
-
layer_b.set_weights(layer_a.get_weights())
와 같은방식으로 쓴다는 것이구나?
-
한번따라해보자.
net.set_weights(net.get_weights())
net.get_weights()
일단 그대로네
_w = net.get_weights()
_w
_w?
type(_w[0])
[_w[0],_w[1]]
아래와 같이 만들면 초기값 만들 수 있겠는걸?
[np.array([[1.2078832]],dtype=np.float32),np.array([[0.]],dtype=np.float32)]
- 길이가 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)
출력은 1 입력은 2(x의 차원이 2니까) bia는 false
net.add(layer)
초기값을 설정하자
net.get_weights()
설정된 것을 바꿔주자
[np.array([[ -5.0],[10.0]], dtype=np.float32)]
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)
벡터니까 X, 신경쓰자
net.weights
-
사실 실전에서는 초기값을 설정할 필요가 별로 없음.
net = tf.keras.Sequential()
layer = tf.keras.layers.Dense(1,use_bias=False,input_dim=2)
ner.set_weights([np.array([[-5.0],[10.0]],dtype=np.float32)])
net.compile(optimizer = tf.keras.optimizers.SGD(0.1),loss='mse')
net.fit(X,y,rpochs=1000,verbose=0,batchsize=200)
(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
tf.losses.MSE(np.array([0.0,0.0,0.0]),np.array([1.0,2.0,3.0]))
(1**2 + 2**2 + 3**2)/3
loss_fn(np.array([0.0,0.0,0.0]),np.array([1.0,2.0,3.0]))*200/3
loss_fn 정의해준거로 봐보면~
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
풀이5보다 조금 편한..?
(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')
내장되어 있는 mse 찾아서 알아서 compile 한다
(4단계) net.fit()
net.fit(X,y,epochs=1000,verbose=0,batch_size=N)
net.weights
net = tf.keras.Sequential()
net.add(tf.keras.layers.Dense(1,use_bias=False))
net.compile(tf.keras.optimizers.SGD(0.1),loss='mse')
net.fit(X,y,epochs=1000,verbose=0,batch_size=200)
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=1000,verbose=0,batch_size=N)
net.weights
- 값이 잘 수렴이 안 된다?
net.optimizer.learning_rate
- 학습률 0.1 에 1000번 돌리면 수렴 잘 되었잖아..
- 근데 기본이 0.01로 되어 있는 기본 학습률.
방법 1) 학습률을 수정한다. 근데 이럴려면 굳이.. sgd옵션 안 쓰는 게 낫지..
net = tf.keras.Sequential()
net.add(tf.keras.layers.Dense(1,use_bias=False))
net.compile(optimizer='sgd', loss='mse')
net.optimizer.learning_rate = tf.Variable(0.1,dtype=tf.float32)
net.fit(X,y,epochs=1000,verbose=0,batch_size=N)
net.weights
방법2) epoc을 늘린다. 하지만 시간이 더 소요되겠지
net = tf.keras.Sequential()
net.add(tf.keras.layers.Dense(1,use_bias=False))
net.compile(optimizer='sgd', loss='mse')
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)
beta_hat이 이게 아닐까? 시도!
yhat = X@beta_hat
plt.plot(x,y,'o')
plt.plot(x,yhat.reshape(-1),'-')
더 좋은 적합선을 얻기위해서!
- loss 값을 가장 작게 하는 선을 찾아보는 것!
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_hats
은 update된 기록해서 beta_hat을 넣기 위한 변수. 업데이트 될 때마다 나오는 beta들의 모임이라 보면 되겠다.
beta_hat = np.array([-3,-2]).reshape(2,1)
beta_hats = beta_hat
beta_hats
(-3,-2) 가 첫 iteration, (2,1) 매트릿이기도 하다. 베타를 모으기 위해 열을 늘려볼까. -> 총 차원은 유지되면서 두 번째 차원 변경 concatenate
- beta_hats의 열을 늘려버려~ 새로운 베타 추가
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)
np.concatenate?
np.concatenate((np.array([[1, 2], [3, 4]]),np.array([[5, 6]]).T),axis=1)
beta_hats
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 - 0.1*slope # 0.1은 적당, 0.3은 쪼금빠르지만 그래도 적당, 0.9는 너무 나간것같음, 1.0 은 수렴안함, 1.2
beta_hats = np.concatenate([beta_hats,beta_hat],axis=1)
0.3이나 0.5는 빨리 loss 값 찾는다고 해서.. 좋은 값이라고 할 수 없다. 1은 수렴하는 듯 터져버리며 수렴 안 함
beta_hats
20번 만에 수럼했네!
beta_hats = beta_hat보다 beta_hats = beta_hat.copy() 가 더 안전한 코드입니다.
- 지금 문제 안 생기는 이유? $\rightarrow$ np.concatenate가 반복실행이 되면서 새로운 object를 만들어서 .copy()와 비슷한 역할을 한다.
- append option을 쓴다? beta_hats 뿐만 아니라 beta_hat 자체도 업데이트되어서 꼬여버리는 현상...
beta_hats[0]
beta_hats[1]
b0hats = beta_hats[0].tolist()
b1hats = beta_hats[1].tolist()
_a,_b = np.meshgrid(np.array([0,1,2]),np.array([4,5,6]))
_a,_b
앞에 array는 행으로 쌓여지고 뒤에 array는 열으로 쌓이네?
_a,_b = np.meshgrid(np.array([0,1,2]),np.array([4,5,6]),indexing='ij')
_a,_b
바뀌었다..?
$loss(\beta_0,\beta_1)$ 에 수월하게 넣기 위해 meshgrid 함수를 사용하자
_a.reshape(-1)
_b.reshape(-1)
$\beta_0$ 과 $\beta_1$의 $N \times 1$ 행렬로 변환
map(lambda x,y: x+y, _a.reshape(-1),_b.reshape(-1))
뭔가 계산이 된다?
list(map(lambda x,y: x+y, _a.reshape(-1),_b.reshape(-1)))
나왔다, _a랑 _b의 각 위치에서의 값들
(y-b0-b1*x)
벡터인데
np.sum((y-b0-b1*x)**2
스칼라 돼
np.linalg.inv(X.T@X) @ X.T @ y
$\beta_0$에 대한 최소값과 $\beta_1$에 대한 최소값
pyhton
ax2.scatter(2.5451404,3.94818596,loss_fn(2.5451404,3.94818596),s=200,marker='*')
여기 넣자
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) # b0hats[0] + b1hats[0]*x 각 초기값들 넣어
# ax2: 오른쪽그림
β0,β1 = np.meshgrid(np.arange(-6,11,0.25),np.arange(-6,11,0.25),indexing='ij') # -6에서 11까지 0.25의 간격으로 만들어줘~ 임의 설정임
β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) # 학습률도 조정해보자 0.1은 적당 0.3은 빠르지만 적당, 0.9는 너무 나감.., 1이면? 수렴하는 듯 터져버림go off
ax2.scatter(2.5451404,3.94818596,loss_fn(2.5451404,3.94818596),s=200,marker='*') # s=200이 의미하는 것은 size지~
def animate(i):
line.set_ydata(b0hats[i] + b1hats[i]*x) # 매 iteration 마다 새로운 선을 왼쪽에 그리자
ax2.scatter(b0hats[i],b1hats[i],loss_fn(b0hats[i],b1hats[i]),color="grey") # 매 iteration 마다 새로운 점을 오른쪽에 그리자
ani = animation.FuncAnimation(fig,animate,frames=30)
ani
학습률 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*slope # 0.1은 적당, 0.3은 쪼금빠르지만 그래도 적당, 0.9는 너무 나간것같음, 1.0 은 수렴안함, 1.2
beta_hats = np.concatenate([beta_hats,beta_hat],axis=1)
b0hats = beta_hats[0].tolist()
b1hats = beta_hats[1].tolist()
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) # b0hats[0] + b1hats[0]*x 각 초기값들 넣어
# ax2: 오른쪽그림
β0,β1 = np.meshgrid(np.arange(-6,11,0.25),np.arange(-6,11,0.25),indexing='ij') # -6에서 11까지 0.25의 간격으로 만들어줘~ 임의 설정임
β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) # 학습률도 조정해보자 0.1은 적당 0.3은 빠르지만 적당, 0.9는 너무 나감.., 1이면? 수렴하는 듯 터져버림go off
ax2.scatter(2.5451404,3.94818596,loss_fn(2.5451404,3.94818596),s=200,marker='*') # s=200이 의미하는 것은 size지~
def animate(i):
line.set_ydata(b0hats[i] + b1hats[i]*x) # 매 iteration 마다 새로운 선을 왼쪽에 그리자
ax2.scatter(b0hats[i],b1hats[i],loss_fn(b0hats[i],b1hats[i]),color="grey") # 매 iteration 마다 새로운 점을 오른쪽에 그리자
ani = animation.FuncAnimation(fig,animate,frames=30)
ani
model: $y_i \approx \beta_0 +\beta_1 e^{-x_i}$
- linear 모델이 확장성이 좋다.
- $\begin{bmatrix} y_1 \\ y_2 \\ \dots \\ y_n \end{bmatrix} = \begin{bmatrix} 1 & exp(x_1) \\ 1 & exp(x_2) \\ \dots \\ 1 & exp(x_n) \end{bmatrix} \begin{bmatrix} \beta_0 \\ \beta_1 \end{bmatrix}$
- $y = X\beta + \epsilon$의 꼴이 될 텐데, $X$를 최소화하는 $\beta$는 여전히 $X^\top (XX^\top)^{-1}Y$ ,,$\beta$ 그대로.
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='*') # 여기도 계산해서 바꿔주자 np.linalg.inv 결과
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)$
exp, cos있으니까 선형 아닌 거 아냐?
- basis가 1, exp(-x),xos(5x)
- coef = beta_0, beta_1,beta_2
- 두 개가 연결되어 있지!
- 연결되어 있어야지!
- 따라서 여전히 linear model이다.
- 적합 가능~
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 # unpacking이라 함
b0hats = beta_hats[0]
b1hats = beta_hats[1]
b2hats = beta_hats[2]
# 같은 결과
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: 오른쪽그림 3차원으로 표현하기 복잡하니 pass하자...
# β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)$
여전히 $y = X \times W$ 이다.
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()
net.add(tf.keras.layers.Dense(1,use_bias=False))
net.compile(tf.optimizers.SGD(0.1),loss='mse')
net.fit(X,y,epochs=50,batch_size=N,verbose=0)
net.weights
plt.plot(x,y,'o')
plt.plot(x,(X@net.weights).reshape(-1),'--')