ML & DL

가중치 초기화의 정의와 방법론

 

본 게시물은 2021.04.15. 에 작성되었으며, 블로그를 이전하며 현재 날짜로 등록되었습니다. 
본 게시물은 CS231n(2017) lecture 6을 공부하며 정리한 내용입니다.
확률통계학 스터디에서 분포에 대해 공부하는 도중, 가중치 초기화에서 분포를 고려했던 점에 대해서 자세히 알아보기로 했다.

 

가중치 초기화(Weight Initialization)

우리는 모델 안에서 가중치를 학습한다.
학습하기 전의 가중치는 어떤 모양일까?

학습하기 전 가중치를 어떤 값으로 설정(초기화)하는 것을 가중치 초기화(Weight Initialization)이라고 한다.
여러 방법을 시도(가정)하면서 어떤 방법이 가장 좋을지 찾아보도록 하겠다.

 

0으로 초기화하자!

만약 모든 가중치를 0으로 초기화한다면 어떻게 될까?

  • 모든 뉴런은 같은 연산을 한다.
  • 그 결과(output) 또한 모두 동일할 것이다.

모두 같은 연산을 해서 같은 gradient를 학습하게 되고, 최종적으로는 모든 뉴런이 동일해질 것이다. 강의에서는 symmetry breaking이 없다고 한다. 동일해지면 대칭이 되기 때문에 이렇게 말했다고 생각한다.
여러 클래스(label)가 있는 문제의 경우 그 클래스에 따라서 마지막에 있는 뉴런이 갖게 될 loss는 각각 다르다. 하지만 0으로 초기화된 가중치를 여러 layer를 거쳐 학습하다 보면 모델 전체를 구성하는 수많은 뉴런들이 동일한 가중치를 갖게 된다.

이런 문제를 해결할 수 있는 다양한 가중치 초기화 방법에 대해 설명하겠다.

 

1. 임의의 작은 값

모든 뉴런을 0으로 초기화했을 때의 단점을 보안하기 위해 symmetriy breaking 역할을 할 수 있도록 아주 작은 값을 랜덤으로 초기화하는 방법은 어떨까?

W = 0.01 * np.random.randn(D,H)

이 방법은 대칭성을 없앨 순 있지만 깊은 신경망에서는 문제가 될 수 있다.

image

10개의 레이어(하나의 레이어에 500개의 뉴런이 있음)에 임의의 작은 값으로 가중치를 초기화 한 후, 각 레이어의 활성화된 값(activation)의 평균과 정규분포를 그린 것이다.
그래프를 보면 알 수 있듯이, 평균은 0에 가깝다. 이는 tanh를 적용했기 때문이다. 정규 분포는 급격히 줄어들다가 0에 수렴하는 것을 볼 수 있다.
이는 막대그래프에서 더 자세히 확인할 수 있는데, 가우시안 분포의 모양을 한 첫번째 레이어 이후에는 평균과 분포 모두 0에 수렴한 모양이다.
그렇다면 어떤 문제를 일으킬까?
학습을 충분히 하기도 전에 0으로 수렴해버리게 되면 우리가 앞서 말했던 0으로 초기화했던 방법과 똑같이 모든 뉴런이 동일한(0) 값을 갖게 된다. gradient를 학습하는 backword pass에서도 gradient가 너무 작기 때문에 거의 update가 되지 않을 것이다.

 

2. 임의의 큰 값

값이 너무 작아서 문제라면 큰 값으로 초기화해보는 건 어떨까?

# 0.01 대신 1.0을 곱해주었다. 
W = 1.0 * np.random.randn(D,H)

image

이 방법의 실험도 1번 방법처럼 tanh를 거치게 했다. 초기화 값이 너무 커서 일어나는 문제는 무엇일까?
모든 뉴런은 saturate(포화)된다.
tanh의 특성 상 모든 뉴런은 -1 혹은 1이 되기 때문이다. (이 부분은 tanh에 대해 정리하면서 더 깊게 공부해야겠다.)
tanh의 특성이자 한계인 갑을 -1 혹은 1로 포화시키고, 결국 가중치는 업데이트되지 않는 문제가 발생할 것이다. 그래프에서 보이는 것처럼 너무 극단적인 부분만 살아남기 때문이다.

 

3. Xavier Initialization

1번, 2번 방법에서 본 것처럼 가중치를 올바르게 초기화하는 것은 어려운 일이다.
너무 작은 값이면 0으로 수렴해 학습이 collapse 될 것이고, 너무 큰 값은 포화(saturate)되기 때문이다.
아직 가중치 초기화에 대한 연구는 활발히 진행 중이지만 지금 우리가 사용하기 적합한 방법은 2010년 Glorot에 의해 연구된 Xavier Initialization이다.

W = np.random.randn(D,H) / np.sqrt(D))  

가우시안 분포에서 샘플을 얻어 input의 수로 스케일링하는 식이다.
이 방법은 input과 output의 분포를 유사하게 만드는 것에 집중된 방법이다.
input이 작은 값이면 작은 값으로 나누고, 큰 값이면 큰 값으로 나누기 때문이다.
우리는 backpropagation을 위해 연산할 때 local gradientupstream gradient 를 하는데 이는 xw가 된다. 때문에 input과 유사한 분포를 유지하는 것이 가능하다.

image

그래프처럼 가우시안 분포를 갖고 싶다면, 가우시안 분포를 이용한 초기화를 사용하면 가능하다!
하지만 ReLU를 사용하면 불가능하다.
ReLU는 0 이하의 값을 모두 0으로 비활성화하기 때문에 제대로 된 분포를 얻을 수 없다.
비활성화되는 뉴런의 수가 적어지기 때문 결국 gradient는 소실된다. 결국 분포가 무너지게 되고 더 많은 뉴런들이 비활성화된다.

 

He initialization

이를 해결하기 위해 다음 수식을 사용할 수 있다.

W = np.random.randn(D,H) / np.sqrt(D/2))  # divided by 2 

사실 왜 2로 나누어 ReLU의 문제를 보완할 수 있었는지 아직 잘 이해가 가지 않는다.
열심히 찾아본 결과 여러 답을 얻었지만 향후 해당 논문, Delving Deep into Rectifiers:
Surpassing Human-Level Performance on ImageNet Classification
을 보고 다시 공부해야겠다. (

지금은 수식을 이해를 못하기 때문에...

)

  1. input(D)을 더 고려해 분산을 두배로 주어 분산을 유지할 수 있다.
  2. ReLU의 특성(음수는 0으로 비활성화, 결국 전체의 1/2를 활성화)을 고려해 2로 나누었다.

 


아직도 가중치 초기화 분야의 연구는 진행 중이라고 한다.
논문의 모든 수식을 스스로 이해할 그 날까지 열심히 해보자!

 

Reference

http://cs231n.stanford.edu/slides/2017/cs231n_2017_lecture6.pdf
https://brunch.co.kr/@kmbmjn95/37
https://kau-deeperent.tistory.com/99

반응형