본문 바로가기

Study doc./Deep Learning

[cs231n] Neural Network - part 1

지난 포스팅에서는 Neural Network의 한 종류인 CNN에 대해서 공부하며 전체적인 프로세스를 익혔습니다.

이번 포스팅에서는 그 과정에 있는 다양한 선택지들과 추가적으로 고려해야 할 사항들을 중심으로 공부해보겠습니다.

 

포스팅은 총 두 파트로 이루어져있고,

첫 번째 파트에서는 활성함수의 종류, 데이터 전처리, 가중치 초기화 방법, 정규화 방법 등 모델링 하기 전의 셋팅과 

하이퍼 파라미터 튜닝 등 학습 도중에 다뤄야 할 과정을 중심으로 작성하겠습니다.

 

두 번째 파트에서는 최적화(Optimization) 알고리즘의 종류, regularization의 종류 등 다양한 선택지들을 중심으로 다뤄보겠습니다.

그럼 시작해볼까요??

 


 

순서

  1. Activation Functions
  2. Data Preprocessing
  3. Weight Initialization
  4. Batch Normalization
  5. Babysitting the Learning Process
  6. Hyperparameter Optimization

 


1. Activation Functions

지난 포스팅에서 activation function의 역할에 대해서 공부했습니다.

간단히 말해 input을 업그레이드 시켜주기 위함인데요, 이 과정이 없다면 아무리 여러층을 쌓아도 결국 하나의 층과 동일한 역할을 하게 됩니다.

그럼 오늘은 이 activation funtion의 종류와 장단점 그리고 실제 많이 사용되는 함수에 대해 알아보겠습니다.

 

먼저 activation function의 대표적인 예시들입니다.

 

1-1. Sigmoid function

 

출력값을 0에서 1로 가지는 시그모이드 함수는 3가지 문제점 때문에 activation function으로 잘 사용되지 않습니다. 

 

1) 첫 번째로 saturated neuron이 gradient를 죽입니다.

이게 무슨 말이냐면,

 

 

L에 대한 x의 영향력을 알아보기위해 backpropagation을 진행했을때 chain rule에 의해 위 두가지 식을 곱해야 합니다.

하지만 saturated 된 지점(x의 절댓값이 큰 구간)에서는 미분값이 0이기 때문에 chain rule의 오른쪽 gradinet 값과는 관계없이 무조건 0이 됩니다. 

따라서 gradient의 업데이트를 못하게 되기 때문에 죽인다(kill)는 표현을 사용합니다.

 

2) 두 번째로 시그모이드의 출력값이 zero-centered 하지 않습니다.

이게 왜 문제냐구요? 

w를 업데이트 하기 위해서는 f 함수에 대한 w의 영향력과 upstream gradient값을 곱하게 되는데,

w와 x를 곱한 형태이기 때문에 f 함수에 대한 w의 영향력은 x 값이 됩니다.

(잘 이해가 안되신다면 이 포스팅을 읽고 와주세요) 

 

이 때 x 값이 zero-centered 하지 않고 항상 양수이기 때문에 w의 업데이트 방향은 항상 upstream gradient의 부호만을 따릅니다. 즉 항상 양수이거나 항상 음수가 되겠죠!

이 현상은 w의 업데이트에 있어 매우 비효율적입니다. 

아래 사진과 같이 파란색의 방향으로 빠르게 업데이트 할 수 있지만, 항상 같은 부호를 가지기 때문에 지그재그로 업데이트 되어야 하기 때문입니다.

 

 

3) 세 번째로 시그모이드 함수에 exponential 이 들어가 계산 비용이 큽니다.

하지만 이 문제는 그다지 큰 이슈가 아니기 때문에 그냥 넘어가도 좋습니다.

 

 

1-2. tanh function

하이퍼볼릭 탄젠트(tanh) 함수의 경우에는 시그모이드 함수의 두 번째 문제였던 zero-centered 문제를 해결했기 때문에 시그모이드 함수보다는 성능이 좋습니다.

하지만 여전히 첫 번째 문제인 kill gradient 문제를 해결하지는 못했다는 한계점이 있습니다.

 

 

 

1-3. LU Family (ReLU, Leaky ReLU, PReLU, ELU)

1) ReLU

ReLU 함수에서 드디어 kill gradient 문제를 해결했습니다(양의 값에서만).

또한 max(0, x) 의 연산으로 속도를 6배 가량 증가시켰습니다. 

 

하지만 zero-centered의 문제가 재발했고, 

음의 값에서는 여전히 kill gradient의 문제가 있다는 한계가 있습니다.

 

 

이렇게 gradient의 절반은 살고, 절반은 죽는 상황에서 층을 쌓아가다보면 종종 dead ReLU 현상이 발생하기도 하는데,

dead ReLU란 다음 그림과 같이 ReLU의 왼쪽에 모든 데이터가 위치하게 되는 상황입니다. 

이렇게 되면 모든 gradient가 0이 되기 때문에 어떤 업데이트도 발생하지 않고 결국 죽어버리게 되는 것이죠.

따라서 ReLU를 사용할 때에는 이 dead ReLU에 유의해야 합니다.

 

 

 

2) Leaky ReLU

Leaky ReLU는 음의 영역에 살짝 기울기를 준 것으로, 

음의 값에서도 kill gradient 문제를 해결할 수 있었습니다.

 

 

 

3) PReLU

PReLU는 Parametric ReLU 로, Leaky ReLU에서 기울기를 학습을 통해 얻는 파라미터로 변경한 것입니다.

이렇게 됨으로써 좀 더 유연한 모델이 되었습니다.

 

 

4) ELU

ELU는 Exponential Lineaer Units 로, ReLU의 모든 장점을 다 가져옴과 동시에 zero-centered 문제도 해결한 함수입니다.

하지만 음의 값에서 kill gradient 문제가 재발했는데요, 이 함수를 개발한 사람의 말과 논문에 따르면 이 문제가 오히려 noise에 강인하다고 합니다.

 

 

 

1-4. Maxout fucntion

Maxout 함수는 두 개의 선형함수를 취하는 함수로써, ReLU의 일반화된 형태라고 할 수 있습니다.

또한 두 선형함수 중 최댓값을 선택하기 때문에 kill gradient 문제가 사라지게 되었습니다.

하지만 파라미터 수가 두배로 증가했기 때문에 딥러닝과 같이 층이 점점 깊어지는 모델에서는 시간과 메모리 소요량이 기하급수적으로 증가한다는 단점이 있습니다.

 

 

 

지금까지 input을 업그레이드 시키는 activation function 의 종류와 특징들을 알아봤는데요,

보통은 ReLU의 성능이 좋기 때문에 가장 많이 사용한다고 합니다.

하지만 절대적인 것은 아니기 때문에 상황에 따라 여러가지 함수를 적용해야 합니다(많은 경험으로 터득).

 

* 주의

- ReLU를 사용할 때에는 dead ReLU의 발생으로 learning rate를 조심해서 다뤄야 함

- 시그모이드 함수는 사용하지 않음

 

 

2. Data Preprocessing

데이터 전처리 방법에는 두 가지가 있습니다.

첫 번째는 평균으로 모두 빼줘서 zero-cetered로 만드는 과정이고,

두 번째는 표준편차로 나눠주어 normalize 하는 과정입니다.

 

 

첫 번째 과정이 없다면 이전에도 말씀드렸듯 gradient의 업데이트가 비효율적인 문제가 발생합니다.

항상 양의 방향 혹은 음의 방향으로 업데이트가 되기 때문입니다.

 

두 번째 과정이 없다면 데이터의 동등한 기여를 고려하지 못하기 때문에 불공평하다는 문제가 발생합니다.

예를 들어 x 축은 년도의 변화, y 축은 시간의 변화라면 y축의 영향에 더 민감하다는 것입니다.

따라서 input 데이터를 활용하기 전에 다음과 같은 데이터 전처리 과정을 거쳐야 합니다.

 

* 팁

- 이미지의 경우에는 픽셀 단위이기 때문에 자체적으로 normalize가 되어있습니다.

- 상황에 따라 평균이 차원별로 계산된 값일 수도 있고, 전체로 계산된 값일 수도 있습니다. 사용자의 판단입니다.

 

 

 

3. Weight Initialization

자, 이제 가중치(Weight) 문제를 생각해보겠습니다.

저희는 이 가중치를 gradient descent 방법을 이용해서 효율적으로 업데이트 하고자 합니다.

왜냐하면 오차값이 최소(손실함수가 최소인 지점)로 하는 가중치를 찾기 위해서였죠.

 

그렇다면 제일 처음의 가중치를 어떻게 설정해야 할까요?

먼저 0으로 한다고 가정해봅시다.

가중치가 모두 0이라면 모든 뉴런이 같은 값으로 업데이트되며, 출력이 모두 같아질 것입니다.

즉 아무리 많은 뉴런이 있다 한들 하나의 뉴런과 같은 성능을 보일 것입니다.

이건 저희가 원하는 결과가 아닙니다.

 

그럼 아주 작은 수로 시작해보는건 어떨까요?

초기 가중치 값을 표준정규분포를 따르는 랜덤한 값에 0.01을 곱해서 정의하겠습니다.

 

오른쪽 파란색 그래프 : layer-mean, 빨간 그래프 : layer-std

 

위 예시는 tanh 를 사용한 neural network 인데요, zero-centered 이기 때문에 평균이 0 주변에 분포가 되어있습니다.

그리고 층이 깊어질수록 평균과 표준편차가 0에 수렴하는 현상을 볼 수 있습니다.

이는 층을 거칠때마다 0.01이 곱해지기 때문입니다.

 

동시에 gradient 값들도 0에 수렴하게 되는데, backpropagation을 생각해보면 f에 대한 w의 영향력이 x값이기 때문에 gradient 역시 점점 작아지게 되는 것입니다. 

따라서 w의 업데이트가 발생하지 않겠죠!

 

그렇다면 가중치의 편차를 0.01이 아닌 1로 설정하면 어떻게 될까요?

가중치 값이 비교적 크기 때문에 w*x 가 커질 것이고, 이는 tanh의 input으로 작용하기 때문에 saturation 될 것입니다.

따라서 출력은 -1또는 1이 되고, gradient는 0이 되기 때문에 gradient의 업데이트는 발생하지 않습니다.

 

 

가중치 초기값이 너무 작으면 gradient가 0으로 수렴하면서 사라져버리고, 

너무 크면 saturation 되어 업데이트가 일어나지 않습니다.

그럼 어떻게 그 중간의 적절한 값을 찾을 수 있을까요?

 

가장 널리 알려진 방법으로 Xavier initialization 방법이 있습니다.

이 방법은 랜덤으로 뽑은 가중치 값을 입력의 수로 나누어 줌으로써 노드의 갯수를 normalize하는 아이디어 입니다.

입력의 수가 많다면 큰 값으로 나눠주고,입력의 수가 적다면 작은 값으로 나눠줘서 입력과 출력의 분산을 맞춰주는 것입니다.

 

 

하지만 Xavier initialization은 선형의 activation을 가정했기 때문에 ReLU 함수에서는 잘 작동하지 않는다고 합니다.

ReLU 함수는 출력의 절반을 날려버리기 때문인데요(출력의 분산 반토막, 값이 점점 작아짐), 

이를 고려하여 He 라는 사람이 입력의 수에 2를 추가적으로 나눠줬더니(전체식에 루트 2를 곱함) 잘 동작했다고 합니다(입력의 절반이 사라지기 때문에 반으로 나눠주는 텀을 추가적으로 더해주는 개념).

 

 

 

4. Batch Normalization

지금까지 가중치 초기화에 대해서 알아보았습니다.

다시 돌아보면 가중치 초기화를 왜 했었죠?

gradient vanishing 문제와 exploding 문제가 발생하지 않게 하기 위해서였습니다.

실제 딥러닝에서 layer를 깊게 쌓을수록 위의 두 문제가 발생하지 않도록 하는 것이 매우 중요한데요,

지금 배울 Batch Normalization 역시 하나의 해결책이 될 수 있습니다.

 

먼저 Batch 라는 것은 샘플링이라고 생각하면 됩니다.

학습 할때마다 모든 데이터를 사용하면 시간이 오래 걸리기 때문에 적당한 크기로 샘플링을 하는 것입니다.

이렇게 샘플링 된 데이터를 정규화 하는 것, 이것을 Batch Normalization 이라고 합니다.

 

활성화함수의 활성화 값 또는 출력값을 항상 표준정규분포에 따르도록 강제하는 작업인데요, 

학습 할때마다 해줘서 모든 layer의 입력이 표준정규분포를 따르도록 합니다.

이로써 gradient vanishing/ exploding 문제를 해결함과 동시에 가중치 초기화의 부담을 덜었습니다.

 

그럼 어떤 기준으로 정규화를 진행할까요?

아래 그림과 같이 Feature(Dimension)별로 정규화를 진행합니다(CNN에서는 activation map 별로)!!

 

 

그럼 어디에 Batch Normalization 을 추가할까요?

Fully connected layer 뒤에 혹은 activation function 전에 추가해주면 됩니다.

딱딱한 규칙이라고 생각하지 말고, layer를 지난 후 새로운 layer의 input 이 될 때 정규화시킨다고 생각하면 됩니다.

 

 

그럼 이런 의문이 생길 수 있습니다.

input을 표준정규분포로 만드는 것이 무조건 좋을까?

tanh 의 saturation 정도를 우리가 정할수 있으면 더 좋지 않을까?

이런 우려로 '감마''베타' 파라미터가 탄생했고, normalize 한 후에 학습되어 계산됩니다.

 

 

여기서 감마는 스케일링 효과, 베타는 이동 효과로,

감마가 표준편차, 베타가 평균값과 같아지는 순간 정규화 하기 전의 값과 같아진다고 할 수 있습니다.

이렇게 감마와 베타를 조절하는 파라미터를 가짐으로써 더 유연한 학습이 가능해졌습니다.

 

Batch Normalization의 과정을 정리해보자면

먼저 미니배치마다 평균과 분산을 계산해주고 normalize를 합니다.

그 후에 추가적으로 감마와 베타를 이용해서 scaling 과 shifting 을 합니다.

(test time에서는 train time에 사용한 평균과 분산을 사용함)

 

 

* Batch Normalization 의 장점

- input을 매번 normalize 하기 때문에 gradient의 흐름이 원활함 -> 학습이 잘됨

- learning rate를 더 키울 수 있음

- 다양한 초기화 방법을 사용할 수 있음

- regularization의 역할을 함 - layer의 출력이 batch 안의 모든 데이터 영향을 받기 때문

 

 

5. Babysitting the Learning Process

지금까지 Neural Network 의 전반적인 구성과 내용에 대해서 배웠습니다.

이제는 코드로 구현하는 과정에 대해 정리해보겠습니다.

 

먼저 데이터 전처리를 합니다(zero-mean). 

그리고 구조를 결정합니다. layer와 뉴런을 얼마나 설정할지를 생각합니다.

이 구조를 토대로 손실함수(loss function)을 정의하고, regularization을 추가했을때 loss 잘 증가하는지 확인합니다.

 

이제 학습을 시켜보기 위해 데이터의 일부를 가져옵니다.

그리고 학습을 반복할수록 loss가 잘 내려가는지 확인합니다.

 

만약 잘 동작했다면 전체 데이터로 시작합니다. 이 때에는 아주 작은 regularization을 줍니다.

가장 먼저 최적의 learning rate를 구해야하는데, 너무 작은면 loss의 변화가 없고, 너무 크면 발산(NaN, inf)해버립니다.

이런 변화를 잘 관찰하며 cross-validation을 통해 최적의 learning rate를 구합니다.

일반적으로 0.01~0.0001 에서 최적값이 나타난다고 합니다.

 

그럼 구체적으로 어떻게 cross-validation 을 하는지 알아보겠습니다.

 

 

6. Hyperparameter Optimization

가장 기본 개념은 적은 반복(epoch)으로 큰 범위를 먼저 탐색한 후, 특정 부분(정확도가 높은 부분)에서 epoch를 늘려 세밀하게 찾는 것입니다.

 

 

하지만 여기서 문제가 있습니다.

파라미터 범위를 세밀하게 조절한 후 validation 정확도를 살펴보니 대체로 learning rate가 10E-4 사이에 존재하고 있습니다.

이렇게 되면 내가 정한 범위의 margin 에 최적값이 나타나고 있다는건데, 사실 10E-5 근처에 존재할수도 10E-6 사이에 존재할 수도 있습니다.

따라서 이런경우 범위를 다시 설정해주어야 합니다.

이상적인 범위는 최적의 파라미터가 범위의 가운데에 위치한 것입니다.

 

* 팁

learning rate는 gradient를 업데이트 할때 곱해지는 값이기 때문에 tuning을 위해 범위를 조절할 때에는 log 스케일로 조절해주는 것이 좋습니다.

 

최적의 파라미터를 찾는 또 다른 방법에는 Random Search 가 있습니다.

Grid Seach는 같은 간격으로 테스트를 하기 때문에 실제 최적의 값을 찾지 못할 확률이 높습니다.

따라서 Random Search가 효과적인 방법이 될 수 있습니다.

 

 

 

마지막으로 파라미터의 감입니다.

 

learning rate의 변화는 빨간색이 가장 이상적입니다. 파란색의 경우에는 gradient의 업데이트 속도가 느리고, 노란색의 경우에는 learning rate가 너무 높아 발산해버리는 현상입니다.

loss 의 경우에는 다음 그림처럼 평평하다가 갑자기 감소하는 그래프가 그려질 수 있습니다. 

이는 가중치 초기화가 잘못되었지만 중간에 학습을 통해 제자리를 찾은 것입니다.

 

 

마지막으로 train set과 test set 의 정확도 차이 입니다.

이렇게 gap이 큰 경우에는 과적합이 된 것이고, regularization을 더 강하게 주어야 합니다.

 

 

지금까지 모델링의 기본적인 구조에 필요한 개념들과 파라미터 튜닝에 대해 공부했습니다.

두 번째 파트에서는 최적화(Optimization) 알고리즘의 종류, regularization의 종류 등에 대해서 다뤄보겠습니다.