빅데이터 분석 특강 (9주차_2) 5월2일
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
import tensorflow.experimental.numpy as tnp
tf.config.experimental.list_physical_devices()
import graphviz
def gv(s): return graphviz.Source('digraph G{ rankdir="LR"'+ s + ';}')
train / test 나눠서 하는 회귀분석, 단순회귀분석이 오버피팅이 아닌 이유basis가 직교하기 때문,
상관계수가 0으로 가기 때문! $\to$ 직교하기 때문에
세미파라메틱모델: 무조건 변수가 많다고 오버피팅이 일어나는 것은 아니다.
직교하는 변수가 3개면 절대 선형결합이 될 수 없다.
색의 삼원색, 빨/파/노 가 각각 basis로 볼 때, 보라색/파란색/빨간색도 basis로 볼 수 있음, 보라색에서 빨간색으로 빼낼 수 있으니까
직선의 베이시스 - 기울기와
오차항을 다 따라가? 오버피팅.. 다시 듣기..
$$y = -2 + 3x_1 + 1x_2 + 0x_3 + 0x_4 + 0.5x_5 $$
$$y = \beta_0 + \beta_1x_1 + \beta_2x_2 + \beta_3x_3 + \beta_4x_4 + \beta_5x_5$$
-
특이한모형: 오버핏이 일어날 수 없는 모형이다.
- 유의미한 coef: 상수항(bias), $\cos(t)$의 계수, $\cos(2t)$의 계수, $\cos(5t)$의 계수.
- 유의미하지 않은 coef: $\cos(3t)$의 계수, $\cos(4t)$의 계수
- 유의미하지 않은 계수는 $n$이 커질수록 0으로 추정된다 = $\cos(3t)$와 $\cos(5t)$는 사용자가 임의로 제외하지 않아도 결국 모형에서 알아서 제거된다 = overfit이 일어나지 않는다. 모형이 알아서 유의미한 변수만 뽑아서 fit하는 느낌
-
3번문제는 overfit이 일어나지 않는다. 이러한 신기한 일이 일어나는 이유는 모든 설명변수가 직교하기 때문임.
- 이런 모형의 장점: overfit이 일어날 위험이 없으므로 train/test로 나누어 학습할 이유가 없다. (샘플만 버리는 꼴, test에 빼둔 observation까지 모아서 학습해 $\beta$를 좀 더 정확히 추론하는게 차라리 더 이득)
- 이러한 모형에서 할일: 추정된 계수들이 0인지 아닌지만 test하면 된다. (이것을 유의성검정이라고 한다)
-
직교기저의 예시
- 빨강과 파랑을 255,255만큼 섞으면 보라색이 된다.
- 빨강과 파랑과 노랑을 각각 255,255,255만큼 섞으면 검은색이 된다.
- 임의의 어떠한 색도 빨강,파랑,노랑의 조합으로 표현가능하다. 즉 $\text{color}= \text{red}*\beta_1 + \text{blue}*\beta_2 + \text{yellow}*\beta_3$이다.
- (빨,파,노)는 색을 표현하는 basis이다. (적절한 $\beta_1,\beta_2,\beta_3$을 구하기만 하면 임의의 색도 표현가능)
- (빨,보,노)역시 색을 표현하는 basis라 볼 수 있다. (파란색이 필요할때 보라색-빨간색을 하면되니까)
- (빨,보,검)역시 색을 표현하는 basis라 볼 수 있다. (파란색이 필요하면 보라색-빨간색을 하면되고, 노란색이 필요하면 검정색-보라색을 하면 되니까)
- (빨,파,노)는 직교기저이다.
-
3번에서 알아둘 것: (1) 직교기저의 개념 (추후 재설명) (2) 임의의 색을 표현하려면 3개의 basis가 필요함
-
그림을 그려보자.
_x= tf.constant(np.arange(1,10001)/10000)
_y= tnp.random.randn(10000) + (0.5 + 2*_x)
plt.plot(_x,_y,'.',alpha=0.1)
-
저것 꼭 10000개 다 모아서 loss계산해야할까?
간격이 10으로 잡혀 건너뛰며 데이터를 가져옴
plt.plot(_x,_y,'.',alpha=0.1)
plt.plot(_x[::10],_y[::10],'.')
-
대충 이정도만 모아서 해도 비슷하지 않을까? $\to$ 해보자!
-
10개의 샘플이 있다고 가정. $\{(x_i,y_i)\}_{i=1}^{10}$ = $(x_1,y_1),\dots, (x_{10},y_{10})$
(epoch1) $loss=\sum_{i=1}^{10}(y_i-\beta_0-\beta_1x_i)^2 \quad \to \quad slope \quad \to \quad update$
(epoch2) $loss=\sum_{i=1}^{10}(y_i-\beta_0-\beta_1x_i)^2 \quad \to \quad slope \quad \to \quad update$
...
경사하강법
(epoch1)
- $loss=(y_1-\beta_0-\beta_1x_1)^2 \quad \to \quad slope \quad \to \quad update$
- $loss=(y_2-\beta_0-\beta_1x_2)^2 \quad \to \quad slope \quad \to \quad update$
- ...
- $loss=(y_{10}-\beta_0-\beta_1x_{10})^2 \quad \to \quad slope \quad \to \quad update$
(epoch2)
- $loss=(y_1-\beta_0-\beta_1x_1)^2 \quad \to \quad slope \quad \to \quad update$
- $loss=(y_2-\beta_0-\beta_1x_2)^2 \quad \to \quad slope \quad \to \quad update$
- ...
- $loss=(y_{10}-\beta_0-\beta_1x_{10})^2 \quad \to \quad slope \quad \to \quad update$
...
여기서 에폭 3번 돌리면 for문도 3번 돌아가..
ver 1과 ver 2의 차이점
- 동일 epoc 대비 효과가 좋은 것은 ver 1
- 동일 iteration 대비 효과가 좋은 것은 ver 1
- 양으로 승부 ver 2 질로 승부 ver 1
계산할 때 조금 더 정확한 방법은 ver 1이라고 할 수 있다.
$m=3$이라고 하자.
(epoch1)
- $loss=\sum_{i=1}^{3}(y_i-\beta_0-\beta_1x_i)^2 \quad \to \quad slope \quad \to \quad update$
- $loss=\sum_{i=4}^{6}(y_i-\beta_0-\beta_1x_i)^2 \quad \to \quad slope \quad \to \quad update$
- $loss=\sum_{i=7}^{9}(y_i-\beta_0-\beta_1x_i)^2 \quad \to \quad slope \quad \to \quad update$
- $loss=(y_{10}-\beta_0-\beta_1x_{10})^2 \quad \to \quad slope \quad \to \quad update$
(epoch2)
- $loss=\sum_{i=1}^{3}(y_i-\beta_0-\beta_1x_i)^2 \quad \to \quad slope \quad \to \quad update$
- $loss=\sum_{i=4}^{6}(y_i-\beta_0-\beta_1x_i)^2 \quad \to \quad slope \quad \to \quad update$
- $loss=\sum_{i=7}^{9}(y_i-\beta_0-\beta_1x_i)^2 \quad \to \quad slope \quad \to \quad update$
- $loss=(y_{10}-\beta_0-\beta_1x_{10})^2 \quad \to \quad slope \quad \to \quad update$
...
미니배치를 만들어서 샘플만큼만 업데이트
여기서 n이 3이면은 ver 1과 같아지지
-
ver1: gradient descent, batch gradient descent
-
ver2: stochastic gradient descent
- 확률적 경사하강법
-
ver3: mini-batch gradient descent, mini-batch stochastic gradient descent
-
ver1: gradient descent
-
ver2: stochastic gradient descent with batch size = 1
-
ver3: stochastic gradient descent
- https://www.deeplearningbook.org/contents/optimization.html, 알고리즘 8-1 참고. p291
note: 이렇게 많이 쓰는 이유? ver1,2는 사실상 없는 방법이므로
Algorithm 8.1 Stochastic gradient descent (SGD) update 위에서 참고한 알고리즘
Require: Learning rate schedule $\epsilon_1, \epsilon_2, \dots$
Require: Initial paramete $\theta$
- $k \gets 1$
- while stopping criterion not met do
- sample a minibatch of m examples from the training set $\{ x^{(1)},\dots,x^{(m)} \}$ with
- corresponding targets $y^{(i)}$.
- Compute gradient estimate: $\hat{g} \gets \frac{1}{m} \nabla_{\theta} \sum_i L(f(x^{(i)} ; \theta), y^{(i)} )$
- Apply update: $\theta \leftarrow \theta - \epsilon_k \hat{g}$
- $k \leftarrow k + 1$
- end while
- while stopping criterion not met do
-
ver2,3에서 샘플을 셔플할 수도 있다.
- ver 3에서 남는 데이터들이 이상치면 어떡해?
-
ver3에서 일부 샘플이 학습에 참여 안하는 버전도 있다.
- 계속 샘플하면 복원이라 안 뽑히는 샘플이 있을 수도 있다.
- n이 커지면 이 영향도 무시할만하게 된다.
-
개인적 생각: 크게 3개 정도만 알면 괜찮고 나머지는 그렇게 유의미하지 않아 보인다.
-
핵심개념
-
메모리사용량: ver1 > ver3 > ver2
- 틀린 설명이 많은 부분..
- 계산속도: ver1 > ver3 > ver2
- local-min에 갇힘: ver1 > ver3 > ver2
- local minimum에 빠졌다가 탈출.. global minimum으로~ 가는 경우도 있다
- local minimum에 갇힌다? = local minimum을 잘 찾는다
-
본질: GPU 메모리가 한정되어 있어서 ver1을 쓰지는 못한다. GPU 메모리를 가장 적게쓰는것은 ver2인데 이것은 너무 불안정하다.
-
틀리진 않지만 어색한 블로그 정리 내용들
- 경사하강법은 종종 국소최소점에 갇히는 문제가 있다. 이를 해결하기 위해서 등장한 방법이 확률적 경사하강법이다.
- 확률적경사하강법도 local minimum애 빠지는 경우가 있는데?
- 전혀 틀린 말은 아지지만 그걸 의도하고 만든 것은 아니다.
- 어쩌다 보니까 확률적 경사하강법이 더 잘 빠져나오는것
- 경사하강법은 계산시간이 오래걸린다. 계산을 빠르게 하기 위해서 등장한 방법이 확률적 경사하강법이다.
- 1회 업데이트는 빠르게 계산함.
- 하지만 그것이 최적의 $\beta$를 빠르게 얻을 수 있다는 의미는 아니다.
- 계산이 빠르단 의미는 1회 업데이트 하는 속도가 빠르다는 의미임. 최종적으루 수렴을 빨리시키는지는 미지수임. 이것은 돌려봐야 안다.
모든 객체를 constant로 불변형 만들면 메모리를 많이 써서 variable 쓴다 했잖아
- 결국 GPU 언제 쓰느냐, gridient를 업데이트할 떄 쓰는!
- gradient 미분하려면 loss 필요하고 , 또 y, yhat이 있어야 하잖아?
- 그런데 메모리 너무 많이 필요
- 그래서 미니배치가 유용하다는 거지
- 나눠서 많이 올릴 수 있으니까
type(tf.keras.datasets.fashion_mnist)
type(tf.keras.datasets.fashion_mnist.load_data)
call call of function
dir(tf.keras.datasets.fashion_mnist.load_data)
a=123.1
dir(a)
위 목록에서 괄호를 열고 닫아 실행되는 코드들
a.__add__(1)
-
tf.keras.datasets.fashion_mnist.load_data()를 이용한 데이터 생성
tf.keras.datasets.fashion_mnist.load_data??
-
함수의 return값을 확인하면 (x_train, y_train), (x_test, y_test)로 결과를 받아야 코드가 예뻐짐을 알 수 있다.
return (x_train, y_train), (x_test, y_test)
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.fashion_mnist.load_data()
-
데이터의 확인
type(x_train)
numpy네
x_train.shape, y_train.shape, x_test.shape, y_test.shape
train 대 test를 6대1로 나눴구나
- x는 60000개의 관측치(이미지의 수)를 가지고 있는듯 보인다.
- 하나의 obs에 대한 x의 차원은 (28,28)이다.
- 하나의 obs에 대한 y의 차원은 스칼라다.
-
하나의 관측치가 무엇을 의미할까?
plt.imshow(x_train[0])
신발을 9라고 정의한 건가!
y_train[0]
- 신발이미지=x, 신발임의의미하는숫자9=y
np.where(y_train==9)
y_train[11]
9나왔다
- y==9인 다른 obs조사
plt.imshow(x_train[11])
역시 신발이 나왔다
신발이 9라고 카테고리화 된것을 조금 더 확신할 수 있겠다.
y_train
x_train.shape
-
$X$: (n,28,28), 픽셀크기가 $28\times28$ 인 이미지
-
${\bf y}$: (n,), 이미지에 대응하는 라벨 (0~9까지의 숫자로 되어있다)
y_train[:20]
-
y=0,1에 대응하는 이미지만 정리하자. (우리가 배운건 로지스틱이니깐)
(x_train[(y_train == 0) | (y_train == 1)]).shape
우리가 계산하기 위해 array로 표현
28*28
y=y_train[(y_train == 0) | (y_train == 1)].reshape(-1,1)
X=x_train[(y_train == 0) | (y_train == 1)].reshape(-1,784)
y,X
yy= y_test[(y_test == 0) | (y_test == 1)].reshape(-1,1)
XX= x_test[(y_test == 0) | (y_test== 1)].reshape(-1,784)
yy,XX
X.shape,y.shape, XX.shape,yy.shape
gv('''
splines=line
subgraph cluster_1{
style=filled;
color=lightgrey;
"x1"
"x2"
".."
"x784"
label = "Layer 0"
}
subgraph cluster_2{
style=filled;
color=lightgrey;
"x1" -> "node1"
"x2" -> "node1"
".." -> "node1"
"x784" -> "node1"
"x1" -> "node2"
"x2" -> "node2"
".." -> "node2"
"x784" -> "node2"
"x1" -> "..."
"x2" -> "..."
".." -> "..."
"x784" -> "..."
"x1" -> "node30"
"x2" -> "node30"
".." -> "node30"
"x784" -> "node30"
label = "Layer 1: relu"
}
subgraph cluster_3{
style=filled;
color=lightgrey;
"node1" -> "y"
"node2" -> "y"
"..." -> "y"
"node30" -> "y"
label = "Layer 2: sigmoid"
}
''')
tf.random.set_seed(43052)
net = tf.keras.Sequential()
net.add(tf.keras.layers.Dense(30,activation='relu'))
net.add(tf.keras.layers.Dense(1,activation='sigmoid'))
net.compile(optimizer='sgd',loss=tf.losses.binary_crossentropy)
net.fit(X,y,epochs=100,batch_size=12000)
net(X)
y
계산된 결과 보니 비슷한 것 같나..
np.mean((net(X)>0.5) == y.reshape(12000,1))
train의 정확률
np.mean((net(XX)>0.5) == yy.reshape(2000,1))
test의 정확률
local minimum에 빠진 것 같음..
초기값이 문제가 아니라, 최적화 방법이 안 좋은 것.. 확률적 경사 하강법..
랜덤 시드에 따라 확연히 달라지는 정확률
tf.random.set_seed(43052)
net = tf.keras.Sequential()
net.add(tf.keras.layers.Dense(30,activation='relu'))
net.add(tf.keras.layers.Dense(1,activation='sigmoid'))
net.compile(optimizer='adam',loss=tf.losses.binary_crossentropy)
net.fit(X,y,epochs=100,batch_size=12000)
np.mean((net(X)>0.5) == y.reshape(12000,1))
train의 정확률
np.mean((net(XX)>0.5) == yy.reshape(2000,1))
adam 쓰니까 확연히 달라진 결과
tf.random.set_seed(43052)
net = tf.keras.Sequential()
net.add(tf.keras.layers.Dense(30,activation='relu'))
net.add(tf.keras.layers.Dense(1,activation='sigmoid'))
net.compile(optimizer='adam',loss=tf.losses.binary_crossentropy,metrics=['accuracy'])
net.fit(X,y,epochs=100,batch_size=12000)
np.mean((net(X)>0.5) == y.reshape(12000,1))
train의 정확률
np.mean((net(XX)>0.5) == yy.reshape(2000,1))
옵션을 넣어야 정확률 쉽게 보는 옵션 사용 가능
net.evaluate(X,y)
train의 정확률
net.evaluate(XX,yy)
metric; 모형이 좋은지 판단할 수 있는 근거
tf.random.set_seed(43052)
net = tf.keras.Sequential()
net.add(tf.keras.layers.Dense(30,activation='relu'))
net.add(tf.keras.layers.Dense(1,activation='sigmoid'))
net.compile(optimizer='adam',loss=tf.losses.binary_crossentropy,metrics=['accuracy'])
net.fit(X,y,epochs=10,batch_size=120)
정확률 높게 시작하는 이유
- 이제까지 업데이트 한 번한 결과인데
- 이 결과는 100번 업데이트한 결과이기 때문에 정확률이 높은 상태에서 시작하게 된다.
net.evaluate(X,y)
train의 정확률
net.evaluate(XX,yy)
tf.random.set_seed(43052)
net = tf.keras.Sequential()
net.add(tf.keras.layers.Dense(30,activation='relu'))
net.add(tf.keras.layers.Dense(1,activation='sigmoid'))
net.compile(optimizer='adam',loss=tf.losses.binary_crossentropy,metrics=['accuracy'])
net.fit(X,y,epochs=10,batch_size=60)
batch_size 60 했더니 200번씩 돌아가네
net = tf.keras.Sequential()
net.add(tf.keras.layers.Dense(30,activation='relu'))
net.add(tf.keras.layers.Dense(1,activation='sigmoid'))
net.compile(optimizer='adam',loss=tf.losses.binary_crossentropy,metrics=['accuracy'])
net.fit(X,y,epochs=10,batch_size=1)
12000번씩 돌아가고 끝나게지..
batch_size 정답은 없다.
64,128,.. 보통 올라가는 배치사이즈로 메모리를 쓰게 놀린다.
과제
tf.random.set_seed(43052)
net = tf.keras.Sequential()
net.add(tf.keras.layers.Dense(30,activation='relu'))
net.add(tf.keras.layers.Dense(1,activation='sigmoid'))
net.compile(optimizer='adam',loss=tf.losses.binary_crossentropy,metrics=['accuracy'])
net.fit(X,y,epochs=10,batch_size=240)