Deep Learning

Batch Normalization 설명 및 구현

NIPS (Neural Information Processing Systems) 는 머신러닝 관련 학회에서 가장 권위있는 학회들 중 하나이다. 이 학회에서는 매년 컨퍼런스를 개최하고, 작년 12월에도 NIPS 2015라는 이름으로 러시아에서 컨퍼런스가 개최되었다. 이 컨퍼런스에 참가한 Brad Neuberg라는 참가자가 있는데, 그가 이 컨퍼런스에서 느낀 10가지 딥러닝 트렌드(원문) 라는 글이 굉장히 화제가 되었었다. 이 트렌드들 중 가장 ‘실용적’ 이라고 느낀 두 가지 트렌드는 다음 두 가지이다.

  1. 거의 모든 state-of-the-art system은 LSTM을 어느 정도 채용하고 있다.
  2. 이제 뉴럴넷 학습에 Batch Normalization은 필수화 되어가고 있다.

이 중에서 이번 글에서 초점을 맞출 부분은 ‘Batch Normalization’ 기법이다. Batch Normalization은 2015년 arXiv에 발표된 후 ICML 2015 (마찬가지로 매우 권위 있는 머신러닝 학회이다) 에 publish 된 이 논문 (Batch Normalization : Accelerating Deep Network Training by Reducing Internal Covariance Shift) 에 설명되어 있는 기법으로, 이 글에서는 이 논문의 내용을 간단하게 요약하고 넘어간 후 Batch Normalization을 실제로 구현하고, 성능을 실험해보는 과정에 대해 서술한다.

Paper

Motivation

Batch Normalization은 기본적으로 Gradient Vanishing / Gradient Exploding 이 일어나지 않도록 하는 아이디어 중의 하나이다. 지금까지는 이 문제를 Activation 함수의 변화 (ReLU 등), Careful Initialization, small learning rate 등으로 해결하였지만, 이 논문에서는 이러한 간접적인 방법보다는 training 하는 과정 자체를 전체적으로 안정화하여 학습 속도를 가속시킬 수 있는 근본적인 방법을 찾고싶어 했다.

이들은 이러한 불안정화가 일어나는 이유가 ‘Internal Covariance Shift’ 라고 주장하고 있다. Internal Covariance Shift라는 현상은 Network의 각 층이나 Activation 마다 input의 distribution이 달라지는 현상을 의미한다. 이 현상을 막기 위해서 간단하게 각 층의 input의 distribution을 평균 0, 표준편차 1인 input으로 normalize 시키는 방법을 생각해볼 수 있고, 이는 whitening이라는 방법으로 해결할 수 있다. Whitening은 기본적으로 들어오는 input의 feature들을 uncorrelated 하게 만들어주고, 각각의 variance를 1로 만들어주는 작업이다.

문제는 whitening을 하기 위해서는 covariance matrix의 계산과 inverse의 계산이 필요하기 때문에 계산량이 많을 뿐더러, 설상가상으로 whitening을 하면 일부 parameter 들의 영향이 무시된다는 것이다. 예를 들어 input u를 받아 x=u+b라는 output을 내놓고 적절한 bias b를 학습하려는 네트워크에서 x에 E[x]를 빼주는 작업을 한다고 생각해보자. 그럴 경우 E[x]를 빼는 과정에서 b의 값이 같이 빠지고, 결국 output에서 b의 영향은 없어지고 만다. 단순히 E[x]를 빼는 것이 아니라 표준편차로 나눠주는 등의 scaling 과정까지 들어갈 경우 이러한 경향은 더욱 악화될 것이고, 논문에서는 이를 실험적으로 확인했다고 한다.

이와 같은 whitening의 단점을 보완하고, internal covariance shift는 줄이기 위해 논문에서는 다음과 같은 접근을 취했다.

  • 각각의 feature들이 이미 uncorrelated 되어있다고 가정하고, feature 각각에 대해서만 scalar 형태로 mean과 variance를 구하고 각각 normalize 한다.
  • 단순히 mean과 variance를 0, 1로 고정시키는 것은 오히려 Activation function의 nonlinearity를 없앨 수 있다. 예를 들어 sigmoid activation의 입력이 평균 0, 분산 1이라면 출력 부분은 곡선보다는 직선 형태에 가까울 것이다. 또한, feature가 uncorrelated 되어있다는 가정에 의해 네트워크가 표현할 수 있는 것이 제한될 수 있다. 이 점들을 보완하기 위해, normalize된 값들에 scale factor (gamma)와 shift factor (beta)를 더해주고 이 변수들을 back-prop 과정에서 같이 train 시켜준다.
  • training data 전체에 대해 mean과 variance를 구하는 것이 아니라, mini-batch 단위로 접근하여 계산한다. 현재 택한 mini-batch 안에서만 mean과 variance를 구해서, 이 값을 이용해서 normalize 한다.

Algorithm

알고리즘의 개요는 위에 서술한 바와 같다. 뉴럴넷을 학습시킬 때 보통 mini-batch 단위로 데이터를 가져와서 학습을 시키는데, 각 feature 별로 평균과 표준편차를 구해준 다음 normalize 해주고, scale factor와 shift factor를 이용하여 새로운 값을 만들어준다. 알고리즘의 개요는 다음과 같다.

BN1
Batch Normalization Transform

실제로 이 Batch Normalization을 네트워크에 적용시킬 때는, 특정 Hidden Layer에 들어가기 전에 Batch Normalization Layer를 더해주어 input을 modify해준 뒤 새로운 값을 activation function으로 넣어주는 방식으로 사용한다.

Network with Batch Normalization. 출처 : http://mohammadpz.github.io

Training Data로 학습을 시킬 때는 현재 보고있는 mini-batch에서 평균과 표준편차를 구하지만, Test Data를 사용하여 Inference를 할 때는 다소 다른 방법을 사용한다. mini-batch의 값들을 이용하는 대신 지금까지 본 전체 데이터를 다 사용한다는 느낌으로,  training 할 때 현재까지 본 input들의 이동평균 (moving average) 및 unbiased variance estimate의 이동평균을 계산하여 저장해놓은 뒤 이 값으로 normalize를 한다. 마지막에 gamma와 beta를 이용하여 scale/shift 해주는 것은 동일하다.

전체적인 Batch Normalization layer의 pseudo-code 는 다음과 같다. 논문에는 다소 헷갈릴 수 있는 방식으로 설명이 되어있는데, 결국 중요한 것은 ‘Training 할 때는 mini-batch의 평균과 분산으로 normalize 하고, Test 할 때는 계산해놓은 이동 평균으로 normalize 한다. Normalize 한 이후에는 scale factor와 shift factor를 이용하여 새로운 값을 만들고, 이 값을 내놓는다. 이 Scale factor와 Shift factor는 다른 레이어에서 weight를 학습하듯이 back-prop에서 학습하면 된다.’ 라는 흐름이다.

BN2.PNG
Batch Normalization Pseudo-code.

단, 지금까지의 설명은 ‘일반적인 Network 일 때’ 에 한해서 통용된다. 만약 Batch Normalization을 CNN에 적용시키고 싶을 경우 지금까지 설명한 방법과는 다소 다른 방법을 이용해야만 한다. 먼저, convolution layer에서 보통 activation function에 값을 넣기 전 Wx+b 형태로 weight를 적용시키는데, Batch Normalization을 사용하고 싶을 경우 normalize 할 때 beta 값이 b의 역할을 대체할 수 있기 때문에 b를 없애준다. 또한, CNN의 경우 convolution의 성질을 유지시키고 싶기 때문에, 각 channel을 기준으로  각각의 Batch Normalization 변수들을 만든다. 예를 들어 m의 mini-batch-size, n의 channel size 를 가진 Convolution Layer에서 Batch Normalization을 적용시킨다고 해보자. convolution을 적용한 후의 feature map의 사이즈가 p x q 일 경우, 각 채널에 대해 m x p x q 개의 각각의 스칼라 값에 대해 mean과 variance를 구하는 것이다. 최종적으로 gamma와 beta는 각 채널에 대해 한개씩 해서 총 n개의 독립적인 Batch Normalization 변수들이 생기게 된다.

Benefit

논문에서 주장하는 Batch Normalization의 장점은 다음과 같다.

  1. 기존 Deep Network에서는 learning rate를 너무 높게 잡을 경우 gradient가 explode/vanish 하거나, 나쁜 local minima에 빠지는 문제가 있었다. 이는 parameter들의 scale 때문인데, Batch Normalization을 사용할 경우 propagation 할 때 parameter의 scale에 영향을 받지 않게 된다. 따라서, learning rate를 크게 잡을 수 있게 되고 이는 빠른 학습을 가능케 한다.
  2. Batch Normalization의 경우 자체적인 regularization 효과가 있다. 이는 기존에 사용하던 weight regularization term 등을 제외할 수 있게 하며, 나아가 Dropout을 제외할 수 있게 한다 (Dropout의 효과와 Batch Normalization의 효과가 같기 때문.) . Dropout의 경우 효과는 좋지만 학습 속도가 다소 느려진다는 단점이 있는데, 이를 제거함으로서 학습 속도도 향상된다.

Implementation

Batch Normalization의 경우 NIPS 2015 10대 트렌드에서 보았듯이 Deep Learning 계에서 필수적인 기법이 되어가고 있다. 나는 Deep Learning 구현에 python과 theano를 쓰는데, Batch Normalization Layer의 경우 Keras에는 이미 구현이 되어있지만 theano에는 아직 구현이 되어있지 않다(0.7.1 에서 추가될 예정이라는듯). 따라서 theano를 이용해서 한번 구현을 해보고 싶기도 하였고, 한번쯤은 실제로 구현을 해봐야 의미가 있을 것 같아 theano를 이용하여 Batch Normalization Layer를 구현해보았다.

구현한 코드는 Github에서 확인할 수 있다. Repo의 readme에 대략적으로 설명이 되어있기도 하지만, BatchNormalization.py 가 가장 핵심적인 Batch Normalization Layer이다. 일반적인 BN과 CNN에서 사용하는 BN을 모두 지원하며, train 시에는 run_mode를 0, test 시에는 run_mode를 1로 설정해주고 돌려야 한다. BNConvLayer.py와 BNMLP.py는 각각 activation 직전, hidden layer 직전에 Batch Normalization을 넣어준 convolution layer / MLP 이다.

논문과 조금 다르게 구현한 부분은 Test의 평균을 구하기 위해 moving average를 구하는 부분이다. 단순히 Moving Average를 구현할 경우, moving average를 구하기 위해서 최근 몇 개 input의 값들을 저장해놓아야 한다는 단점이 있다. 새로운 moving average를 계산할 때 가장 오래된  이를 방지하기 위해, 그냥 moving average 대신 exponential moving average 를 적용하여 값을 저장해놓지 않고도 moving average를 계산할 수 있도록 하였다.

Experiment

Batch Normalization Layer 를 구현해 보았으니, 실제로 뉴럴넷 학습에 Batch Normalization이 얼마나 강력한 효과를 가지는지 실험을 통해 확인해보았다. 실험은 간단하게 MNIST Dataset을 이용하여, Batch Normalization 을 적용한 네트워크와 그렇지 않은 네트워크의 성능 차이를 비교해보았다. MNIST Data의 전처리는 Global Contrast Normalization만 해주었다.

코드 상으로는 normalCNN.py 가 일반적인 네트워크, BNaddedCNN.py 가 Batch Normalization을 적용한 네트워크를 가지고 MNIST Classification을 진행하는 코드이다. 두 실험 모두 네트워크의 규모는 동일하다. 두 네트워크 모두 convolution layer 3개(channel은 각각 32개, 64개, 128개) 와 max-pool layer 2개, 그리고 마지막에 hidden layer 800개 – output layer 10개 짜리 MLP를 달아준 간단한 Convolutional Neural Network이다. 다만 차이점의 경우 normalCNN에서는 Convolution Layer들 사이에 Dropout Layer를 하나 달아주고 MLP에 Dropconnect를 적용하였으며, BNaddedCNN에서는 Drop 들을 다 제거하고 Convolution Layer와 MLP에 Batch Normalization을 적용하였다.

일단 같은 learning rate를 적용했을 때의 결과를 비교해보자. learning rate를 0.002로 잡았을 때, 단순한 CNN과 Batch Normalization을 적용한 CNN의 성능 비교 그래프이다.

BN3

결과 그래프를 보면 두 네트워크 사이에 확연히 성능의 차이가 존재하는 것을 알 수 있다. 같은 learning rate에서 학습을 진행했음에도 불구하고, Batch Normalization을 적용한 네트워크의 에러율이 일반 CNN의 에러율 그래프보다 훨씬 아래에 존재한다. 또한, epoch 1만 진행했을 때도 에러율이 3.19% / 1.65%로 반 정도로 차이가 난다. 적당히 성능을 비교하기 위해 약 25 epoch 정도만 학습을 진행했는데, 이 과정에서 가장 낮은 Validation Error Rate는 각각 0.92% / 0.78%로 Batch Normalization을 적용한 네트워크 쪽이 더 낮았다.

위에서 설명한 Batch Normalization의 장점중에는 높은 learning rate를 잡을 수 있다는 특징도 있었다. 이를 실험해보기 위해, 기존에 실험했던 learning rate의 10배인 0.02의 learning rate로도 비교실험을 진행해보았다. 이를 진행해보니 Batch Normalization에서는 특이한 점 없이 계속 에러율이 내려간 반면, 일반적 CNN에서는 gradient explode가 일어나 90%의 에러율을 보였다(에러율이 90%라는 것은 값이 폭발하여 NaN 등이 발생하고, 이에 따라 정상적인 값이 나오지 않았음을 의미한다).

마지막으로, Batch Normalization 을 적용한 Network에 0.01의 learning rate를 주고 빠른 learning rate decay를 적용하여 긴 시간동안 학습을 진행시켜 보았다. 총 300 epoch 동안 학습을 진행시켰으며, 최종적으로 학습을 마쳤을 때 MNIST Test Data의 Error rate는 0.6% 였다. 이 실험은 데이터의 preprocessing / augmentation, careful hyper-parameter selection 없이 진행되었으며 비교적 shallow한 CNN를 이용하여 진행하였으므로, 이것저것 처리를 해주고 네트워크 구조를 바꾸어 준다면 더 낮은 에러율을 얻을 수 있을거라고 확신한다.

BN4
최종적으로 돌려본 Batch Normalization Network의 Validation Error Rate 그래프. 300 epoch 후의 최종적 Test error rate는 0.6%였음.

Closing

Batch Normalization을 공부하고, 구현하고 실험해봄으로서 이 ‘각 layer 당 normalize를 해준다’ 라는 비교적 간단한 아이디어가 네트워크 학습의 성능을 얼마나 향상시킬 수 있는지에 대해 직접 체감할 수 있었다. Batch Normalization이 필수적인 트렌트가 되고 있다는 증언까지 있는 만큼, 딥 러닝에 관심이 있는 사람이라면 이 기법에 대해 알아놓으면 좋을 것 같다.

최종적으로 Batch Normalization과 이 글의 내용을 정리해보자면,

  • Batch Normalization에서는 각 layer에 들어가는 input을 normalize 시킴으로써 layer의 학습을 가속하는데, 이 때 whitening 등의 방법을 쓰는 대신 각 mini-batch의 mean과 variance를 구하여 normalize한다.
  • 각 feature들이 uncorrelated 되어있다는 가정의 효과를 없애주기 위해, scaling factor와 shifting factor를 layer에 추가로 도입하여 back-prop으로 학습시킨다.
  • Theano로 Batch Normalization을 구현하였다.
  • MNIST Dataset으로 실험한 결과 Batch Normalization 기법이 실제로 학습을 가속화하고, 이에 따라 학습의 성능을 향상시킬 수 있다는 것을 실험적으로 확인하였다.

 

Advertisements

Batch Normalization 설명 및 구현”에 대한 12개의 생각

  1. 학습과정에서 전체이동평균으로 정규화하지않고 해당 배치의 평균만으로 정규화하는 이유는 뭘까요..
    그러면서 테스트할때는 계산된 전체 이동평균을 사용하는데..
    그럼 어떤 배치의 평균이든 이동평균으로 수렴한다는 보장이 있는건가요?

    좋아요

  2. 논문리뷰를 시작했는데, Local response noramlization 과 Batch normalization에 대해서 공부하려는 중입니다. 정리 솜씨가 빼어나시네요, 좋은글 작성해주셔서 감사합니다. 잘 보고갑니다.

    좋아요

  3. whitening이 parameter 영향을 무시한다기 보다는, Back propagation 과정에서 whitening 연산의 영향이 포함되지 않으면 model이 blow up 한다는 이야기 같습니다

    좋아요

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중