본문 바로가기
Deep Learning/모두를 위한 cs231n

[모두를 위한 cs231n] Lecture 6. Weight Initialization

by Steve-Lee 2020. 5. 18.

안녕하세요 Steve-Lee입니다. 지난 시간에 이어 Lecture 6. Training Neural Network에 대해 배워보도록 하겠습니다. 이번 시간에는 Weight Initialization에 대해 배워보도록 하겠습니다. 

 

모두를 위한 cs231n

더보기

모두를 위한 cs231n 😀

👉🏻 시작합니다! 🎈

모두를 위한 cs231n (feat. 모두의 딥러닝 & cs231n)


👉🏻 Neural Network 기초 📗
* Backpropagation
Lecture4. Backpropagation and Neural Network. 오차역전파에 대해서 알아보자😃


👉🏻 Training Neural Network Part I 📑

- Activation Function 파헤치기

Lecture 6. Activation Functions에 대해 알아보자 
Lecture 6. Activation Functions - ReLU함수의 모든 것

 

- Data Preprocessing

Lecture 6. Training Neural Network - Data Preprocessing

 

- Weight Initialization 

Lecture 6. Weight Initialization

 

- Batch Normalization
Lecture 6. Batch Normalization

 

👉🏻 Deep Learning CPU와 GPU ⚙️

Lecture 8 - Part1. Deep Learning 을 위한 CPU와 GPU


👉🏻 Deep Learning Framework ☕️
Lecture 8 - Part2. Deep Learning Framework

👉🏻 TensorFlow Fraemwork 🧱
Lecture 8 - Part3. TensorFlow Framework


👉🏻 
PyTorch Framework 🔥

Lecture 8 - Part3. PyTorch Framework

 

👉🏻 Generative Model

Lecture 13 - Part2. VAE(Variational AutoEncoder)

 

모두를 위한 cs231n (feat. 모두의 딥러닝 & cs231n)

cs231n 시작합니다! 안녕하세요. Steve-Lee입니다. 작년 2학기 빅데이터 연합동아리 활동을 하면서 동기, 후배들과 함께 공부했었던 cs231n을 다시 시작하려고 합니다. 제가 공부하면서 느꼈던 점들과

deepinsight.tistory.com

 

Part I Index

Weight Initialization

 

Two Layer Neural Network의 예제를 다시 한번 보도록 하겠습니다. 우리가 할 일은 가중치 업데이트입니다.

가중치 업데이트는 다음과 같습니다. 맨 처음에 어떤 초기 가중치가 있으며 gradient를 계산하면서 가중치를 업데이트시킵니다.

첫 번째 질문입니다. '모든 가중치=0'이면 어떻게 될까요? 즉 모든 파라미터를 0으로 세팅하면 어떻게 될까요?

 

학습이 안되지 않을까요?

입력값에 대한 출력 값이 모두 0이기 때문에 backprop도 안되지 않을까요??

 

모든 뉴런이 죽어버리고 update가 되지 않습니다.

⇒ 정확한 답은 아닙니다.

 

모든 뉴런이 <같은 일>을 한다는 것은 맞습니다. 그렇다고 죽어버리지는 않습니다.

 

가중치가 0이라서 모든 뉴런은 모두 다 같은 연산을 할 것입니다.

결국 gradient가 같을 것이고 모든 뉴런이 똑같이 업데이트될 것입니다.

 

이게 바로 뉴런을 똑같이 0으로 초기화했을 때 발생하는 문제입니다.

각 뉴런들이 어떤 클래스에 연결되어 있는지에 따라 뉴런들이 서로 다른 loss를 가질 수는 있습니다.

 

하지만 네트워크 전체를 보면 많은 뉴런들이 동일한 가중치로 연결되어 있을 것입니다. 결국 모든 뉴런이 같은 방식으로 업데이트될 것이고 이는 문제가 될 것입니다.

 

📌 기억하세요

W=0 → 모든 뉴런이 같은 방식으로 업데이트 → 역전 파시 가중치 update도 동일하게 발생

 

가중치 초기화 방법 1

First Idea: Small random numbers

초기화 문제 첫 번째 방법은 작은 랜덤 값으로 초기화시켜주는 것입니다.

 

이 경우 초기 W를 표준 정규분포(standard gaussian)에서 샘플링합니다.

좀 더 작은 값을 위해 스케일링을 해줍니다. 0.01을 나눠 표준 편차를 1e-2, 즉 0.01로 만들어줍니다.

여러분의 네트워크가 작은 네트워크라면 이 정도면 충분할 것입니다. 하지만 이 방법은 더 깊은 네트워크에서 문제가 생길 수 있습니다.

 

  • 첫 번째 방법
    • 특징
      • 평균 0, 표준편차 0.01인 가우시안 분포
      • 가우시안 분포에 따른 랜덤 파라미터 초기화
    • 단점
      • Small data에서는 잘 동작하지만 activation 함수를 넣은 Deep Network에서는 잘 작동하지 않습니다

 

하나씩 살펴보도록 하겠습니다.

다음의 code를 통해 Weight Initialization을 살펴보겠습니다

레이어마다 500개의 뉴런을 가지고 있는 10개의 레이어를 통해 살펴보도록 합니다.

비선형 활성화 함수로는 tanh를 사용합니다. 그리고 가중치는 '임의의 작은 값'으로 초기화시킵니다.

 

각 레이어별 activation 수치를 통계화시켜보겠습니다.

첫 번째 레이어의 출력 분포를 보면 평균은 항상 0 근처에 있습니다. 하지만 레이어가 진행될수록 표준편차는 급격하게 줄어들게 됩니다. 그리고 맨 밑에 똑같은 분포를 띄게 됩니다.

 

문제는 우리가 W를 곱하면 곱할수록 W가 너무 적은 값이라서 출력 값이 급격히 줄어드는 것입니다. (Over and over again)

 

그래서 모든 Activation이 0이 됩니다.


그렇다면 backpropagation은 어떻게 될까요?

 

Think about the backward pass. What do the gradients look like?

 

Q. gradient는 어떻게 될까...??

 

 

W가 아주 작은 값인 경우 뉴런의 각 입력값은 엄청 작은 값입니다. 입력 값은 점점 0에 수렴합니다. 이때 Backprop을 생각해보면 upstream gradient가 점점 전파됩니다.

 

현재 가중치를 업데이트하려면 upstream gradient에 local gradient를 곱해주면 됩니다. WX를 W에 대해 미분해보면 local gradient는 입력 X가 됩니다. 이렇게 되면 앞서 다루었던 문제와 비슷한 문제가 생기게 됩니다.

X가 엄청 작은 값이기 때문에 gradient도 작을 것이고 결국 업데이트가 잘 일어나지 않을 것입니다.

 

  • Backprop시 문제점
    • 입력 값들이 거의 0에 가까워지므로 Backprop시 문제 발생
    • Upstream gradient X Local gradient 연산 시 0에 가까워짐
    • 따라서 Weight Update가 거의 일어나지 않음

이런 실험은 gradient의 흐름이 네트워크에 어떤 영향을 미치는지 생각해 볼 수 있는 좋은 예시입니다.

이제 forward pass의 형태를 살펴보고는 이런 경우 gradient가 어떤 식으로 전파되는지 짐작할 수 있을 것입니다. 그리고 다양한 입력 타입에 따라 weight와 gradient가 어떤 영향을 미치는지도 생각해 볼 수 있겠습니다.

또한 gradient가 chaining(연결)되면서 어떤 식으로 전파되는지 생각해본다면 gradient를 backprop 하는 과정은 반대입니다. upstream gradient에 W의 gradient인 X를 곱합니다. 입력 X은 어떤 내적의 결과입니다. 그리고 backward pass의 과정에서 upstream gradient를 구하는 것은 현재 upstream에 가중치를 곱하는 것입니다. 우리는 W를 계속해서 곱하기 때문에 Backward pass에서도 Forward처럼 gradient는 점점 작아지게 됩니다. 따라서 upstream gradient는 0으로 수렴하게 됩니다.


자 그렇다면 가중치를 좀 더 큰 값으로 초기화하면 어떨까요?

가중치 초기화 방법 2

second Idea: Weight 0.01 → 0.1

 

어떤 문제가 일어날까요?

 

이제 가중치가 큽니다. 이렇게 큰 가중치를 통과한 출력 WX를 구하고 이를 tanh를 거치게 한다면 어떻게 될까요??

 

값은 saturation 될 것입니다. 가중치가 큰 값을 가지므로 tanh의 출력은 항상 saturation 될 것입니다. 그렇게 되면 다음과 같은 결과를 확인해 볼 수 있습니다.

 

위의 결괏값에서 볼 수 있듯이 출력이 항상 -1이거나 +1이 됩니다.

다시 말하지만 입력값이 tanh 활성화 함수를 거치는 과정에서 saturation 될 것이고 gradient는 0이 될 것입니다. 즉 가중치 업데이트가 일어나지 않을 것입니다.

 

적절한 가중치 초기화 방법

이처럼 적절한 가중치로 초기화하는 것은 어려운 방법입니다. 그래서 연구자들은 어떻게 하면 가중치 초기화를 잘할 수 있을까에 대한 많은 고민을 했습니다. 널리 알려진 방법은 Xavier Initialization입니다.

Xavier Initialization

먼저 슬라이드 맨 위의 W에 대한 수식을 살펴보도록 하겠습니다.

W = np.random.randn(fan_in, fan_out) / np.sqrt(fan_in)

Standard gaussian으로 뽑은 값을 '입력의 수'로 스케일링해줍니다.

기본적으로 Xavier Initialization이 하는 일은 입/출력의 분산을 맞춰주는 것입니다.

 

수식을 통해 이해할 수 있는 것은 입력의 수가 적으면 더 적은 값으로 나누고 좀 더 큰 값을 얻습니다.

 

그리고 우리는 더 큰 가중치가 필요합니다. 왜냐하면 작은 입력의 수가 가중치와 곱해지기 떄문에 가중치가 더 커야만 출력의 분산 만큼 큰 값을 얻을 수 있기 떄문입니다. 반대로 입력의 수가 많은 경우에는 더 작은 가중치가 필요합니다.

 

각 레이어의 입력이 Unit gaussian이길 원한다면 이런 류의 초기화 기법을 사용해 보실 수 있습니다.

 

여기서 가정하는 것은 현재 Linear activation이 있다고 가정하는 것입니다. 가령 tanh의 경우 우리가 지금 tanh의 active region안에 있다고 가정하는 것입니다.

 

Lecture Note를 보시면 더 자세히 이해할 수 있습니다.

  • [ ] 다음 목표는 Lecture Note 파헤치기...!

문제가 하나 있습니다. ReLU를 사용하면 잘 작동하지 않습니다. ReLU는 출력의 절반을 죽입니다. 결국 출력의 분산을 반토막 내버립니다. 그러므로 이전과 같은 가정을 하면 ReLU에서는 잘 작동하지 않습니다. 값이 너무 작아지는 것입니다.

보이시는 것처럼 ReLU를 사용할 경우 분포가 또 줄기 시작했습니다. 이 문제를 해결하기 위한 일부 논문이 있는데 본 논문에서는 추가적으로 2를 더 나눠줬습니다.

 

뉴런들 중 절반이 없어진다는 사실을 고려하기 위해 2를 나눠준 것입니다.

이렇게 되면 입력은 반밖에 안 들어갈 때 반으로 나눠주는 Term(2)을 추가적으로 더해주는 것이고 실제로 잘 동작을 하게 됩니다.

결과를 보시면 전체적으로 좋은 분포를 형성하고 있는 것을 볼 수 있습니다.

실제로 이 작은 변화는 트레이닝에 있어서 엄청난 차이를 보여줍니다.

 

TLDR;

지금까지 Weight 초기화 방법에 대해 알아보았습니다.

  • Weight를 초기화해야 한다면 'Xavier Initialization'을 사용하는 것을 적극 추천합니다.

 

한편 본 Lecture와 Lecture Slide는 2017년 발표자료로 지금으로부터 3년 전의 자료입니다. 2020년 Lecture Note를 공부하여 그동안 발전된 내용들에 대해서도 소개해드리도록 노력해보겠습니다.

 

긴 글 읽어주셔서 감사합니다. 오늘 하루도 좋은 하루 보내세요! 

 

Reference

  • cs231n Lecture 6 강의 및 강의 슬라이드
  • cs231n Lecture Note

댓글