3 분 소요

Pytorch나 Keras를 사용하여 딥러닝 모델을 만들다보면 어떤 타입의 레이어를 쓸지, 또 레이어의 차원은 어떻게할지, 배치 사이즈는 어떻게 할지 등 하이퍼파라미터 세팅 위주로 신경쓰게 된다. 정작 중요한 파라미터, 즉 실제로 학습이 되는 벡터들은 어떻게 초기화해야할지 신경 안쓰고 곧바로 nn.Linear를 쌓게 된다. 그런데 이 하이퍼파라미터 초기화가 학습 속도는 물론, 모델 최종 성능에도 영향을 미칠 수 있는 만큼 확실하게 정리해 본다. 항상 그렇듯 강의나 블로그 글을 그대로 한국어로 (번역도 아닌) 해석한 포스트가 아니라, 여러 강의 자료와 논문, 블로그 글을 읽은 뒤 나 나름대로 정리한 내용이다.

reference

  1. Stanford CS231n–Training Nerual Networks 1
  2. DeepLearning.ai–Initializing neural networks
  3. 365 Data Science

activation

효과적인 가중치 설정법을 이해하려면 순전파와 역전파 과정과 활성화 함수를 복습할 필요가 있다. 우선 아핀 레이어에서 순전파는 \(z = \mathbf{XW}\) 로 이뤄지고 역전파시 로컬 기울기는 \(\frac{\partial{z}}{\partial{\mathbf{W}}} = \mathbf{X}\) 이다. 가중치 \(\mathbf{W}\) 값과 상관없이 레이어의 인풋 \(\bm{X}\) 값으로만 가중치 업데이트가 된다는 건데 왜 가중치 초기값을 고민해야하는지 의문이 들어야 한다. 그 이유는 딥러닝 모델의 힘은 레이어를 2층 이상 쌓는 데서 나오고, 역전파 시 필요한 \(\frac{\partial{loss}}{\partial{\X}} = \mathbf{W}\) 이기 때문이다. 즉 어떤 뉴런의 가중치가 0이면 해당 뉴런에 연결된 이전 레이어의 뉴런들(또 이 뉴런들에 연결된 뉴런들)이 업데이트 되지 못하게 된다.

zero-centering

현재 많이 사용되는 He 초기화나 Xavier 초기화는 모두 평균이 0인 분포에서 가중치를 끌어오는 방법이다. 왜 평균이 0인게 중요할까? 직관적으로도 양수로만 혹은 음수로만 가중치를 세팅하는 것보다는 양수, 음수, 0 섞어서 초기화하는 게 좋을 것 같긴 한데 수학적으로도 그럴까? 만약에 선형 레이어의 인풋 벡터의 모든 요소가 양수라면 어떻게 될까? 이 레이어의 로컬 기울기는 \(\mathbf{X}\) 이므로 벡터의 모든 요소가 양수이다. 이 층의 로컬 기울기가 양수이기 때문에 누적 기울기(이번 레이어부터 출력 레이어까지의 로컬 기울기들을 곱한 값)는 chain rule에 따라 무조건 양수 또는 음수가 된다. 이 말은 이 레이어에 있는 모든 뉴런들의 가중치는 무조건 양수 또는 음수 방향으로 업데이트가 되어야 하고 업데이트 안되는 경우(로컬 기울기가 0)는 없다는 뜻이다. 즉 효과적인 학습을 보장하지 못한다.

zig-zag weight update
W가 2차원일 때 파란선이 목표인데, 무조건 양수 또는 음수 방향으로 업데이트가 이뤄지고 있다. 출처: CS231n

saturation

딥러닝에선 활성화 함수가 함수의 최댓값이나 최솟값에 가까운 출력값을 낼 때 saturation이 일어났다고 한다. sigmoid 활성화 함수를 생각해보면 입력값이 조금이라도 크거나 작을 때 0에 가까운 기울기값을 갖게 되고, 다중의 레이어로 이뤄진 딥러닝 모델에서 gradient vanishing 문제를 일으킬 수 있다. 즉 활성화 함수에 따라 saturation이 일어나지 않도록 가중치를 관리해 주는 것이 중요하다.

초기화

0으로 초기화?

그래서 레이어의 모든 가중치를 0으로 초기화 하는 것은 어떨까? 뉴런의 가중치가 0이면 훈련이 불가능할까? 나도 처음엔 0으로 초기화하면 무조건 뉴런이 죽는다고 생각했는데, 사실은 그렇지 않다. 다시 한번 말하자면 가중치의 로컬 기울기는 해당 레이어가 받는 인풋 값 그 자체이기 때문에 가중치와는 상관이 없고 가중치가 0이여도 뉴런은 죽지 않는다. 다만 활성화 함수가 ReLU일 때는 모든 레이어의 모든 유닛의 w와 b가 0으로 초기화되면, 0에서 미분이 불가능한 ReLU 함수의 특성 때문에 문제가 된다. 0이든 아니면 0이 아닌 어떤 값이든 같은 값으로 초기화하면 안된다. 한 레이어가 복수의 뉴런으로 이뤄진 이유는 각 뉴런이 각자 다른 가중치를 갖고 같은 인풋에서 각기 다른 특성(패턴)을 읽어내게끔 하는 것인데, 이 뉴런들이 다 같은 가중치를 갖게 되면 사실상 하나의 뉴런과 다름이 없게 된다.

정규분포로 초기화?

그렇다면 동일한 상수가 아닌 정규분포에서 샘플링한 값들로 초기화를 하면 어떻게 될까? 실제로 2010년 전까지 평균이 0이고, 표준편차가 0.1(즉 분산은 0.01)인 분포를 자주 이용했다고 한다 (출처: reference 3). 주의할 점은 당시까지만 하더라도 sigmoid나 tanh 활성화 함수를 썼다는 것이다. image

정규분포에서 샘플링한 가중치를 곱해 얻어낸 값들이 sigmoid 함수 정의역의 중간 부분에 뭉치게 되는데, 이 부분은 선형 함수에 가까운 부분이라 활성화 함수의 비선형성을 제대로 누리지 못한다. 또 가중치를 키워 sigmoid 함수의 극단쪽으로 가면 이번엔 역전파 시 vanishing gradient 문제가 생긴다. 본질적으로 층이 깊은 모델의 경우 층을 지나면서 이전 층의 출력이자 이번 층의 입력인 \(X\)가 너무 커지거나 작아지게 되는데, 이 역시 gradient exploding 또는 vanishing 문제를 일으킬 수 있으며 또 가중치 업데이트 관련하여 층마다의 영향력이 불균형해진다는 문제점을 갖는다 (아주 큰 값의 W를 가진 레이어들로 X를 계속 키우면 맨 마지막 레이어에서 W의 로컬 기울기, 즉 X는 맨 처음 레이어의 로컬 기울기보다 훨씬 크게 되고 여러 층을 쌓는 의미가 없어진다).

Xavier 초기화 (GLorot 초기화)

결국 바람직한 초기화는 1. 평균이 0이고 2. 모든 레이어의 연산마다 분산이 일정해야 한다는 것이다. Xavier 초기화는 평균이 0이고 분산이 \(\frac{1}{\sqrt{fan^{in}}} \text{ (단, fan^{in}은 이전 층의 뉴런 수)}\) 인 정규분포를 이용하여 가중치를 생성한다. output 차원을 고려해 살짝 변형시킨 \(\sqrt{\frac{2}{fan^{in} + fan^{out}}}\) 로 분산값을 정하는 것도 가능하다 (\(fan^{in} == fan^{out}\) 시에 원래 분산값과 같다). w와 b가 각각 i.i.d. 이고 서로 독립적이며, 활성화 함수가 sigmoid라는 가정으로 식을 유도하는 복잡한 과정은 여기를 참고하면 된다. 직관적으로 이해하자면, 차원이 커질수록 분산도 커지니 입력층(과 출력층)의 차원 크기에 반비례하게 분산 크기를 조절하여 레이어마다 비슷한 분포를 이용하게끔 하는 것이다. Xavier 초기화는 정규분포를 이용하는 방식 외에도 균등 분포를 이용한 구현도 가능하다.

\[\mathbf{W} \sim \mathcal{U}(- \sqrt{\frac{6}{fan^{in}+fan^{out}}}, \sqrt{\frac{6}{fan^{in}+fan^{out}}})\]

주의할 점은 Xavier 초기화가 애초에 sigmoid, tanh 활성화 함수를 전제로 식을 유도했기 때문에 ReLU 함수와 쓸 경우에는 효율이 떨어진다고 한다.

He 초기화

He 초기화는 Xavier 초기화의 변형으로 ReLU 함수와 써도 괜찮기 때문에 최근 많이 사용된다고 한다. He normal 초기화는 Xavier normal 초기화와 비슷하게 평균이 0이지만, 분산을 키운 (\(Var(W) = \sqrt{\frac{2}{fan^{in}}}\) ) 분산을 이용한다.

업데이트: