본문 바로가기
코딩 독학/CS231n

[cs231n] 6강. Training Neural Network 1

by 효니루 2020. 11. 14.

✔ 본 포스팅은 20/10/10 ~ 20/12/26 동안 진행하는 가짜연구소 딥러닝기초이론스터디를 통해 학습한 내용입니다.

 

✔ 본 포스팅은 스탠포드 대학의 cs231n 강의를 정리한 내용입니다.

 

##이해수반 내용정리 추가하기##


개요

이제까지는 딥러닝이 어떻게 작동하고 구현되는지에 대한 원리를 살펴보았다.

오늘은 그러한 원리를 이용해 딥러닝을 설계할 때 우리가 주의깊게 설정하고 구성할 단계들과 파라미터 등에 대하여 본다.

 

1. Activation functions

2. Data preprocessing

3. Weight initialization

4. Batch normalization

5. Babysitting the learning process

6. Hyperparameter optimization

 

1. Activation functions

1-(1) 개요

먼저 활성함수이다.

CNN의 layer를 쌓을 때, 한 층의 layer에도 뉴런이라 부르는 위의 동그란 노드를 여러개 구성하는데,

그 안에서의 연산은 2가지 과정을 거침을 우리는 전 수업에서 배웠다.

  1)  합성곱, linear 한 계산, score구하기   2) 이 score를 활성함수 f에 넣어 ouput으로 출력

 

이 활성함수 f에는 다양한 함수가 사용될 수 있는데, 기본적으로 비선형(non-linear)함수를 사용한다.

이유는 linear한 일차함수를 사용한다면 아무리 여러 layer의 연산을 거쳐도 일차함수형태를 벗어날 수 없기 때문에, 여러층의 노드를 쌓는 의미가 없어지기 때문이다.

 

1-(2) 활성함수의 종류 6가지

✔종류 모아보기 ↓

더보기

1) Sigmoid 함수           4) Leaky ReLU함수

2) Hypertanh 함수        5) PReLU함수

3) ReLU 함수               6) ELU함수     7) Maxout

1) Sigmoid 함수

 

- 사용 : 최종출력층에서 사용

 

단점 :

① 기울기소실

② zero-centered가 아니다.

③ exp() 연산은 컴퓨터입장에서 연산부담이 커진다.

 

 

 

 

단점 중 ①과 ②를 하나씩 살펴보며 이 함수의 특징을 알아보자.

1)- ① 기울기소실 (Gradient vanishing)

 

sigmoid 함수의 그래프 모양은 왼쪽과 같다.

x = 0일때 기울기 = 1/4로 최대이고, 약 x= -5 ~ 5 이외의 범위에서는 기울기가 거의 0에 근접한다.

 

backpropagation을 시행할때 $w2 = w2 - \alpha\frac{dL}{dw2}$로 기울기를 갱신하는데, 이 때 x가 -10이거나 10일때를 예를 들자면, 시그모이드 함수에서의 기울기 즉 $\frac{dL}{dw2}$ 가 거의 0이 되어 해당 노드의 기울기는 소실된다.

 

 

뿐만 아니라 x=0일 때조차도 기울기 = 1/4이기 때문에, backpropagation을 여러번거치게 되면 이때의 기울기 또한 결국 0으로 수렴할 가능성이 크다.

1)-② 함수가 zero-centered 가 아니다.

 

 

 

 

zero-centered : 함수가 0이 중심인 함수 (0을 기준으로 대칭)

 

 

 

 

 

설명 추가하기

간단하게 노드가 1개, 1층 layer에 input 3개가 각각 w1, w2, w3 가중치로 들어온다고 해보자.

바로 위의 식대로 $\frac{dL}{df}$ 와 $\frac{dL}{dw_i}$ 의 부호는 항상 같아야 하고,

$\frac{dL}{df}$ 의 부호가 결정되면, 모든 i에 대한 $\frac{dL}{dw_i}$ 의 부호는 같아야 하므로

위의 경우 w1, w2, w3의 부호가 모두 같아야 한다.

 

이 때, 역전파로 기울기를 update할 때, w1과 w2의 최적의 업데이트 방향이

파란색 선과 같이 w1은 (+) w2는 (-) 방향으로 가는 경우라고 '가정'했을 때

이 경우, w1과 w2는 항상 같은 방향의 부호를 갖게 되므로,

파란색 방향으로 바로 이동하지 못하고 (+)(+) 또는 (-)(-) 방향으로 거쳐서 지그재그 방향으로 내려가게 되는 비효율성이 발생한다.

 

 

 

 

2) Hypertanh 함수

 

- sigmoid함수의 zero-centered문제를 개선

 

- 하지만 여전히 기울기소실과, exp()함수의 연산부하로 잘 사용하지 않음.

 

 

 

 

 

 

3) ReLU 함수

- ReLU함수 는 0이하에서는 0, 0보다 클 때는 y=x인 함수이다.

- 장점 : x>0 이면 기울기가 소실되지 않는다는점, 연산도 간단하다는 점, 앞의 두 함수보다 빠르게 수렴한다는 점 등의 장점으로 가장 흔하게 사용하는 활성함수이다.

 

- 단점

① x < 0의 경우 기울기를 버리게 된다.

② 여전히 non zero-centered 함수이다.

③ x = 0에서 미분불가능하다.

 

특히 ①번 문제는 기울기가 0인 뉴런(노드)이 발생해 그 뉴런은 죽었다! 라는 의미의 dead ReLU 라는 현상을 일으키게 되는데, 이는 흔하게 다음 두가지 상황에서 발생한다.

dead ReLU 발생  _ 이런경우가 10~20%는 발생

1) weight 초기화의 실수

2) α (learning rate) 가 높을 때

 

⇒ 대처방법 : ReLU 뉴런을 초기화할 때 bias 를 0 이 아닌 작은수로 흔히 0.01로 초기화하기도 한다. 하지만 아직 논쟁중인 부분

 

4) Leaky ReLU함수

- ReLU에서 x<0 인 경우의 기울기를 살리기 위해 변형을 준 함수

- x<0에서 y = 0.1x 의 함수를 띤다.

- 기울기소실 문제를 해결가능하나 아직 확실히 검증되지 않은 함수

5) Parametric Rectifier (PReLU) 

- 그림엔 없지만, Leaky ReLU함수에서, x<0일때의 기울기를 0.1이 아닌 α로 설정하여 이 기울기 또한 역전파를 통해 학습하는 함수

6) ELU 함수

- ReLU의 장점에서 기울기소실문제도 없애고, zero-centered한 함수

- 단점 : exp()연산이 남아있다.

7) Maxout 함수

굉장히 특이한 함수인데, 뉴런 1개에 weight를 2개 부여하여 계산한다. 때문에 연산이 2배걸린다는 단점이 있다.

하지만 성능은 제일 좋다고도 한다.

 

1-(3) 활성함수 요약

- 기본적으로는 ReLU 함수를 사용한다.

- 실험해보고 싶다면 ReLU, Maxout, ELU 를 사용한다.

- hypertanh 는 거의 사용하지 않고, sigmoid는 대부분 ouput layer에서 사용한다.

 

2. Data preprocessing 

아무리 좋은 딥러닝 네트워크라고 해도 데이터가 좋지 못하면 쓸모가 없다. 좋은 데이터를 만들기 위한 데이터전처리과정에 대해 살펴보자.

2-(1) 기본방법

1) Zero-centered → normalization

- Zero-centered : input 데이터의 평균값을 빼준다.

- normalization : 이를 표준편차로 나눠서 정규화시켜준다.

=> 정규화의 목적은 데이터값들을 특정 범위안으로 변환해주기 위함이다. 데이터값들의 편차가 너무 심하면 분석이 힘들기 때문이다. 단, 이미지데이터의 pixel값들은 이미 0-255 사이의 값이기 때문에 정규화를 할 필요가 없다.

 

2) PCA (Principal Component Anlysis) → whitening

- PCA (주성분분석) : data를 비상관화하여 차원을 줄인다.  # 비상관화? 찾아보기

- whitening : 인접한 pixel의 중복성(redundancy)를 줄인다.  # 찾아보기

=> 이 또한 이미지에 큰 의미가 없어서 안 한다고 한다.

 

2-(2) 이미지데이터의 전처리 : zero-centered Only

① mean image를 빼주는 방법 : 픽셀별로 [32, 32, 3] ndarray의 연산

② 채널별 mean을 빼주는 방법 : RGB 별로 3개의 연산

=> 연산과정상 ②번 과정이 더 편리하다.

 

 

3. Weight initialization

먼저 w = 0으로 초기화할 경우, 모든 뉴런이 동일한 연산을 하게 된다. 따라서 우린 w를 적당히 다른 값으로 초기화할 필요가 있다.

Weight 는 뉴럴네트워크를 설정할 때 중요한 hyperparameter이기 때문에 중요한데, 초기화하는 방법이 여러개 있다.

하나씩 살펴보고, 어떤 방법이 제일 좋은지 알아보자

3-(1) small random number 초기화

- w를 랜덤으로 굉장히 작은수로 설정해주는 방법!

- np.random.randn(D, H) 함수를 사용하여

  평균=0, 표준편차=0.01인  가우시안 정규분포에서 랜덤하게 DxH개만큼 수를 뽑고, 0.01을 곱해 작은 수를 만들어준다.

 

💫 실제적용

> 코드 ↓

더보기
# weight initialization
import numpy as np
D = np.random.randn(1000, 500) # 500개 노드 10층 layer
hidden_layer_sizes = [500]*10   # [500, 500, 500, 500, 500, 500, 500, 500, 500, 500]
nonlinearities = ['tanh']*len(hidden_layer_sizes)

# 정방향전파
# X = (1000, 500), W = (500, 500), H = np.dot(X,W) = (1000,500) 
act = {'relu': lambda x:np.maximum(0,x), 'tanh': lambda x: np.tanh(x)  }  
Hs = {} # 각 layer의 output 
for i in range(len(hidden_layer_sizes)):  # 10층 (0~9)
    X = D if i == 0 else Hs[i-1]  # 0층(input layer)은 초기D를 input으로 받고, 그 다음층부터는 직전layer의 output을 input으로 받는다.
    fan_in = X.shape[1] # 500
    fan_out = hidden_layer_sizes[i] # i번째 layer의 size (모두 500임)
    W = np.random.randn(fan_in, fan_out)*0.01 # 각 layer의 W를 작은수(*0.01)로 랜덤초기화, shape=(500, 500)

    H = np.dot(X, W) # score, 가중합, (1000,500)
    H = act[nonlinearities[i]](H) # 활성함수, nonlinearity
    Hs[i] = H # Hs에 i번째 layer의 ouput ndarray를 추가!

print('input layer 평균:{0:.5f}, 표준편차:{1:.5f}'.format(np.mean(D), np.std(D)))
layer_means = [np.mean(H) for i, H in Hs.items()]
layer_stds = [np.std(H) for i, H in Hs.items()]
for i, H in Hs.items():
    print('hidden layer 평균:{0:.5f}, 표준편차:{1:.5f}'.format(layer_means[i], layer_stds[i]))


# 히스토그램
import matplotlib.pyplot as plt
%matplotlib inline

plt.figure()
plt.subplot(1,2,1)
plt.plot(layers, layer_means, 'bo-') #bo- : blue, 원형, 선연결 marker사용
plt.title('layer mean')
plt.subplot(1,2,2)
plt.plot(layers, layer_stds, 'ro-')
plt.title('layer std')

plt.rcParams["figure.figsize"] = (20,4)
plt.figure()
for i, H in Hs.items():  # H = (1000,500) ndarray 
    plt.subplot(1, len(Hs), i+1 ) 
    plt.hist(H.ravel(), 30, range=(-1, 1))

 

 

위의 코드를 살짝 설명하자면!

각 hidden layer에 input으로 X=(1000, 500) 가 들어오고

각각 W=(500, 500) 가중치로 가중합스코어를 구한뒤

활성함수 tanh(x)를 적용해 output X=(1000, 500)를 출력해

다음 layer에 넣어주는 뉴럴네트워크를 생성해준다.

 

 

 

 

> 결과

이렇게 실행했을 때의 결과를 그래프로 시각화했다.

1. 위쪽그래프 : 10개의 layer의 output의 각원소의 평균, 표준편차를 구했다. 4번째 layer정도 넘어가니 거의 0에 수렴

2. 아래쪽그래프 : 각 층의 데이터분포 (H) 를 그린 히스토그램이다. 3번째 layer정도부터 확실히 표준편차=0에 수렴해 평균=0에 데이터들이 수렴하는 모습이 보인다.

 

=> x들이 0으로 수렴하게 되면 가중치 역전파에서 dW1 = X * dW2 일때, X에 들어가는 원소들이 0에 가까워지니, 결국 dW1도 0에 수렴한다.

=> vanishing gradient 가 발생!

 

3-(2) 큰수로 초기화 : W = np.random.randn( ) *1 로 초기화

 

- 위와 다르게 매우작은수가 아니라 1을 곱해서 초기화했을 때

- X는 -1 또는 1로 수렴한다.

- 결국 W gradient도 0으로 수렴!

∵ loss가 변하지 않음

 

 

 

3-(3) Xavier initialization 방법 : 

 

- input수 (fan_in)으로 나누어 초기화

- input수가 작으면, W가 크고, input수가 크면, W가 커진다.

 

- hitogram을 보면 x가 saturation 발생하지 않고 좋다!

- 단, ReLU에서 문제가 생기더라.

 

 

 

3-(4) 카이밍헤 방법 : ReLU에서도 좋음 => 현재 가장 많이 쓰인다.

 

결론

1. ReLU에서 weight initialization할 때는 카이밍헤의 방법이 최고라는 것

weight 초기화는 아직도 연구가 활발하고 넘어야 할 산이 많은 분야라고 한다.

 

이 문제의 돌파구로 제시된 해결책이 바로 다음것이다.

 

4. Batch Normalization

- 딥러닝에서는 수많은 hiden layer를 거치면서, 초기데이터의 분포가 변하게 된다.

- 학습데이터와 테스트데이터셋의 분포가 다르면 예측이 적절히 이루어지지 않듯이, 뉴럴네트워크에서도 layer마다 들어오는 데이터의 분포가 달라지게 되면 적절한 학습이 이루어지지 않는다.

- 이를 교정하기 위해 두가지 방법 ① careful weight initialization ② small learning rate 을 사용하지만 학습속도가 느려지거나 쉽게 조절이 안 되는 단점이 있다.

- 이를 해결하기 위해 매층마다 데이터의 분포를 재조절해주는 Batch Normalization이 등장한다. 

 

개념이해 Internal covariate shift

출처 : https://youtu.be/TDx8iZHwFtM 의 동영상강의를 참고하여 설명*

 

- 앞서 말했듯이 은닉층을 거듭할 때마다 초기 input과 분포가 변하고, 

- 은닉층이 깊어질수록 그 차이는 커진다.

- 이것을 internal covariate shift라고 한다.

 

 

 

 

 

 

실제로 하나의 층에는 wx의 가중합을 거친 후 활성함수계산을 하여 최종 hidden layer의 출력값을 구하게 되는데, 이 때 weight값에 따라 그림의 기존 데이터분포인 노란색곡선에서 초록색곡선분포로 변할 수 있다. 이 때 Batch Norm을 활용하면 분포의 변이를 줄일 수 있다.

 

 

 

Batch Normalization 방법

여기서 Batch란 전체 데이터를 세트를 나눠서 학습시킬때, 은닉층에 들어온 데이터세트를 말한다.

  1. 정규화 : 배치데이터의 평균, 분산을 이용해 정규화

  2. scale(범위조정), shift(이동) : scale을 위해 $\gamma$, shift에는 $\beta$ 값을 하이퍼파라미터로 사용하고, backpropagation을 통해 이 값들 또한 학습한다.

 

오른쪽그림에서, 기존데이터 노란색분포가 배치놈을 거치지 않고 은닉층을 지나면 초록색분포로 변한다고 할때,

데이터가 오른쪽으로 치우쳤고(shift), 기존의 0을 중심으로 분포한 것에 비해 범위도 넓어졌다. 

배치놈을 이용해 데이터를 평균=0, 분산=1인 분포를 유지할뿐만 아니라, scale and shift를 이용해 치우치고 넓어진 분포를 다시 옮겨온다.

+scale and shift

$$y_i \leftarrow \gamma\hat{x_i} + \beta$$

데이터를 정규화시키는 것만으로 부족한 이유를 간단히 설명한다.

왼쪽은 ReLU, 오른쪽은 시그모이드함수의 곡선이다. 은닉층에서 이러한 활성함수에 들어가기 전 가중합에 대한 배치놈을 적용하게 된다. 파란색화살표를 활성함수에 들어가게 되는 가중합이라고 했을때!

 

1. ReLU함수 : 기본 정규화만 거쳐 평균=0, 분산=1인 분포를 가졌을때 왼쪽 범위의 절반은 출력값이 0으로 소실된다.

   => 이런 경우 살짝 오른쪽으로 shift하고, scale을 넓혀서 죽는 값을 줄여주기 위함이다.

2. 시그모이드함수 : 활성함수를 거치는 이유는 뉴럴네트워크연산에서 nonlinear한 연산을 통해 복잡성을 높이기 위함인데 (합성함수를 계속 쌓아서 안되던 분류도 되게 한다는 의미) scale이 너무 좁아버리면 함수특성상 거의 linear해진다.

이때는 vanishing gradient가 되지 않을 범위까지 scale을 좀 넓히기도 한다.

+scale and shift 역전파 계산

출처 : https://youtu.be/TDx8iZHwFtM

chain rule에 의해 loss에 대한 파라미터들의 도함수를 구한식이다. 아따 증말 어렵다잉... 그러니 포인트인 $\gamma$와 $\beta$ 를 보고 넘어가자! (직접구하다가 3,4번째 줄에서 막혔는데,, 구해보면 chain rule이 더 심도있게 와닿긴 한다)

 

$\gamma \hat{x_i} + \beta = y_i $ 의 식에서 

$$\frac{\partial l}{\partial \gamma} = \Sigma_{i=1}^{m} \frac{\partial l}{\partial y_i} * \frac{\partial y_i}{\partial \gamma} = \Sigma_{i=1}^{m} \frac{\partial l}{\partial y_i} * \hat{x_i}$$

 

아래의 $\beta$ 에 대한 식은 같은 방식으로 구하면 저렇게 나온다.

 

 

요약

(1) 효과

초기화에 의존하지 않아도 된다.

② gradient 가 개선된다.

learning rate 가 커도 허용되고, 그에 따라 학습이 발라진다.

regularization의 효과도 있다.

⑤ drop out을 안해도 된다 : 근데 실제로는 drop out도 하면 성능이 좋아서 많이들 같이 쓴다고 함.

 

(2) 주의할 점

- 단, batch 정규화를 할 때에는 train set와 test set에서 살짝 기준이 다르다.

- train data는 batch 기준 mean을 이용하고, test data는 train을 거친 후 전체 data의 mean를 이용해 정규화를 한다.

 

6. Learning process

직접 시행해보는 과정인데, 시행해보고 다시 올리자!

7. Hyperparameter

우리가 중점적으로 tuning하는 Hyperparameter는 learning rate와 regularization이다.

이 때 tuning을 무작정 아무 숫자나 넣고 할 수는 없다.

두 가지 방법이 있다.

random search 방법과, Gridsearch 방법인데 주로 사용하는 random-search 방법을 먼저 보고 두 방식의 차이점을 알아보자.

 

7-(1) random search method

1) 먼저 반복수(epochs)를 낮게 하여 적당한 reg, lr를 구한다.

- reg와 lr을 10의 몇승 형태로 표현하였다. log space화 시켜 연산이 편리하게 해주는 효과가 있다.

- uniform함수는 그 안의 범위의 랜덤한 scalar값을 반환한다.

2) 그 후 높은 val_accuracy를 갖는 lr, reg를 골라 그에 맞게 lr과 reg의 범위를 조금 더 줄여서 시행해본다.

- 위에서 lr = 4.2 x 10^-04 , reg = 6.6*10^-01 에서 좋은 acc가 나왔으니, lr의 제곱승 범위를 (-3, -4)로, reg 의 제곱승 범위를 (-4, 0)로 좁혀서 다시 해보았다.

- 여기서 붉은 글시 부분을 보니, val_acc는 높아졌지만, lr이 설정한 범위의 boundary에 너무 근접한 값이 나왔다. 범위를 조금 더 넓혀보아도 된다는 시그널이다.

 

7-(2) GridSearch 

- Grid Search는 주어진 범위를 랜덤이 아닌 등간격으로 탐색한다는 점에서 random search와 차이점이 있다.

- 이 경우 특정부분의 특징을 가진 parameter가 무시되기 때문에 random search 방법이 선호된다.

 

7-(3) monitoring with tuned hyperparameters

이렇게 hyperparameter를 튜닝하고 3가지를 중점적으로 모니터링한다.

1) loss curve : 이를 통해 loss convergence의 속도를 본다.

2) accuracy : loss는 그 자체로는 어떤 의미를 띠지 않지만, accuracy는 이 자체로 의미를 띠기 때문에 좋은 모니터링 대상이다.

3) w update의 크기 / w 전체 크기 = 1/1000이 이상적

 

 

 


출처

www.youtube.com/watch?v=wEoyxE0GP2M&list=PLC1qU-LWwrF64f4QKQT-Vg5Wr4qEE1Zxk&index=6

댓글