반응형

**towardsdatascience.com의 [기사]

**
다음 블로그 [링크1], [링크2], [링크3], [링크4]의 내용을 보충자료로 활용함**

**

Different Types of Normalization in Tensorflow

설명과 구현으로 텐서플로의 batch, group, instance, layer 그리고 weight 정규화에 대해 배워보자.

[이미지 소스]

딥러닝에서 정규화(normalization)이 소개되었을 때, 이는 다음으로 큰 것이었고 성능을 상당히 개선했다. 올바르게 이를 가져오는 것은 모델의 중대한 요소가 될 수 있다. 도대체 배치 정규화(batch normalization)이 무엇이고 어떻게 성능을 개선하는지에 대한 의문을 가진적이 있다. 또한 어떤 대체 방법이 있는가? 만약 이런 의문이 있었지만 결코 신경쓰지 않고 단지 모델에서 사용만 했다면 이 글이 명확하게 만들어 줄 것이다.  

Table of Contents


Batch Normalization

배치(batch)단위로 정규화하는 것으로 batch 크기의 영향을 많이 받는다. 아래식은 일반적으로 사용되는 평균(mean)과 표준편차(standard deviation)을 구하는 식이다.

$\mu_i = \frac{1}{m}\sum_{k\in S_i}x_k$

$\sigma_i = \sqrt{\frac{1}{m}(x_k - \mu_i)^2 + \epsilon}$

$\hat{x} = \frac{1}{\sigma_i}(x_i - \mu_i)$

$y_i = \gamma \hat{x}_i + \beta$

  • $\mu$ : (미니배치) 평균

  • $\sigma$ : (미니배치) 표준편차

  • $\hat{x}$ : 정규화

  • $y_i$ : scale and shift

  • $i$ : 특성(feature)

  • $\epsilon$ : 아주 작은 값(1e-5). x와 평균 $\bar{x}$가 같을 경우, 0이 되는 것을 방지.

  • $\text{S}$ : 평균과 표준편차가 계산된 픽셀의 집합.

  • $\gamma$ : scale

  • $\beta$ : shift

    예를 들면, 2D 이미지에서 i는 (iN, iC, iH, iW)이고 4개의 벡터(N, C, H, W)를 갖게 된다. 배치 정규화에서는 미니배치 크기(N)에 대해 각각의 특성(C, H, W)의 평균과 표준편차를 이용해 정규화한다. $\gamma$와 $\beta$의 학습 가능한 파라미터를 갖는데, 이는 zero 평균과 단위 표준 편차(unit standard deviation)을 갖는 것과 관련된 문제 해결을 위해 사용된다.

데이터를 계속 정규화하게 되면 활성화 함수의 비선형 같은 성질을 잃게 되는데 이러한 문제를 완화하기 위해 scale과 shift를 사용한다. 예를들어, 아래 그림의 sigmoid 함수의 경우, 입력값 N(0, 1)이므로 95%의 입력값은 sigmoid 함수의 그래프 중간 $(x=(-1.96, 1.96)\text{구간})$에 속하고 이 부분은 선형이기 때문에 비선형 성질을 잃게 된다. 따라서 이러한 성질을 보존하기 위해 scale과 shift연산을 사용한다.

좀 더 자세한 내용은 다음 [블로그]의 내용을 참고하자.

[unit standard deviation]

데이터 특성을 원래 유닛(miles, dollars,...)에서 표준 편차의 단위(unit of standard deviation)로 변환하고 있다는 의미.

예를 들어, 다음과 같은 가상상의 데이터에서 침실수(integer unit)과 크기(squared meters unit)의 두 특성으로 집의 가격을 예측한다고 하면,

import numpy as np x = np.array([[1, 65], [3, 130], [2, 80], [2, 70], [1, 50]])

각 특성(침실수와 크기)은 매우 다른 평균과 표준 편차를 갖는다.

print("mean={}, std={}".format(x.mean(axis=0), x.std(axis=0))
결과는
mean=[ 1.8 79. ], std=[ 0.74833148 27.27636339]

위와 같이 크기 특성은 침실 수보다 30배 이상 더 큰 평균과 표준편차를 갖는다. 이런 경우 큰 값을 갖는 특성 때문에 작은 값을 갖는 특성이 반영되지 않는 몇몇 알고리즘(neural nets, svm, kmm 등과 같은)에서 왜곡이 발생하게 된다. 이를 해결하기 위한 방법으로 zero평균을 갖는 표준편차로 아래와 같이 데이터를 변환한다.

x_t = (x - x.mean(axis=0)) / x.std(axis=0)

변수 x_t(변형된 x)는 zero 평균으로 단위 표준 편차에 특성을 포함한다. x_t를 출력하면 아래와 같다.

[[-1.06904497 -0.5132649 ] [ 1.60356745 1.86975072] [ 0.26726124 0.03666178] [ 0.26726124 -0.32995601] [-1.06904497 -1.06319158]]

양쪽 특성내 숫자가 얼마나 모두 동일한 크기를 갖는지 보기 위해 x_t의 평균과 표준편차를 출력하면 아래와 같이 평균은 0, 표준편차는 1인 것을 알 수 있다.

mean=[-8.8817842e-17 0.0000000e+00], std=[1. 1.]

이 모든 것은매우 간단해 보이지만 왜 커뮤니티에 그같은 큰 영향을 미쳤고 어떻게 이렇게 할 수 있는 것일까? 답은 완전하게 밝혀지지 않았다. 몇몇은 내부 공변량 이동을 향상시킨다고 말하는 반면 일부는 그에 동의하지 않는다. 하지만 이것이 손실 표면을 더 매끄럽게 만든다 그리고 하나의 레이어의 활성화는 다른 레이어로부터 독립적으로 제어될 수 있고 가중치가 사방으로 날라가는 것을 방지할 수 있다.

배치 사이즈가 작을 때, 미니배치의 평균(mean)/분산(variance)은 전체(global) 평균/변량과 다를 수 있다. 이는 많은 노이즈를 나타낸다. 만약 배치 크기가 1이라면 배치정규화는 적용될 수 없고 RNN내에서 동작하지 않는다.

Layer Noramlization

아래 왼쪽 그림과 같이 배치 정규화가 배치 단위로 정규화를 수행하는 반면 오른쪽의 레이어 정규화는 입력 데이터의 (1회) 반복마다 평균과 표준편차를 구한다.

$S_i = \{k | k_N = i_N \}$

 이후에 다루는 그룹 정규화와 그룹과 인스턴스 정규화와 같이 이것은 한번에 하나의 이미지에서 동작한다. 즉, 평균/분산이 다른 예제(데이터)와 독립적으로 계산된다. 실험에서는 RNNs에서 잘 동작한다는 결과를 보였다.

Instance Normalization

각 훈련 이미지의 각 채널에 대한 편균/분산을 계산한다. Style transfer를 위해 고안된 방법이기 때문에 style transfer에서 배치 정규화를 대체하여 많이 사용하고, GANs에서 배치 정규화를 대체하여 사용된다.

$S_i = \{k | k_n = i_N, k_c = i_c \}$

Group Noramlization

그룹 정규화는 레이어 정규화와 인스턴스 정규화의 중간쯤의 성격으로 채널을 그룹지어 그룹단위로 정규화하는 방법이다. 즉 입력 데이터 각각에 대해 채널을 그룹으로 나누고 이 그룹을 기준으로 평균과 표준편차를 계산하여 정규화한다. 따라서 배치 크기와 상관없이 동작한다.

$S_i = \{k|k_N = i_N, [\frac{k_C}{C/G}] = [\frac{i_C}{C/G}] \}$

Group 개수 또한 유동적으로 변경되는 값으로 논문에서는 32개의 그룹으로 만드는 것이 가장 좋은 결과를 보였다고 한다. 이미지가 고해상도이고 메모리 제약 때문에 큰 배치사이즈를 사용할 수 없는 경우, 그룹 정규화는 효과적인 방법이 된다. 앞의 레이어 정규화와 인스턴스 정규화는 이미지 인식 작업에서 배치 정규화에 미치지 못한 결과를 보이지만, 그룹 정규화는 그렇지 않다. 인스턴스 정규화 이후 레이어로 이어지는 단일 채널만을 고려하고 있는 반면 레이어 정규화는 모든 채널을 고려한다. 하지만, 모든 채널은 동일하게 중요하지 않지만 서로 완전하게 독립적이지도 않다. 그룹 정규화는 이 두가지의 방법을 장점을 혼합한 방법으로 볼 수 있다.

Weight Normalization

\[[논문](https://arxiv.org/abs/1602.07868)\]에서는 아래와 같이 설명하고 있다.

이 방법으로 가중치(weight)를 다시 파라미터화(reparameterize)하는 것에 의해, 최적화 문제의 조건(condition)을 개선하고 SGD(Stochastic Gradient Descent)의 수렴을 가속한다. 재파라미터화는 배치 정규화에서 영감을 받았지만 미니배치내의 예제간에 어떠한 의존도 도입하지 않는다. 이는 이 방법이 배치 정규화가 덜 적합한, LSTMs과 같은 재귀적(recurrent) 모델과 심층 강화학습(depp reinforcement learning) 또는 생성 모델(generative model) 같은 노이즈에 민감한(noise-sensitive) 어플리케이션에 성공적으로 적용될 수 있다. 비록 모델이 훨씬 간단하지만, 여전히 전체 배치 정규화의 속도 향상을 제공하고 모델의 계산에 관한 오버헤드는 낮다. 그리고 동일 시간에 더 많은 최적화 단게를 수행한다.

어렵다. 그래서 다른 자료를 찾아보니 상대적으로 쉽게 설명된 글을 찾아 간략하게 정리해본다.

Weight Standardiztion(WS)의 아이디어는 매우 간단하다. 배치/레이어/인스턴스/그룹 정규화와 같은 기존 기법은 주로 feature activation을 대상으로 정규화를 수행하는 반면, WS는 weight(convolution filter)를 대상으로 정규화를 수행한다.

자세한 내용은 다음 [블로그]의 내용을 참조하자.

Implementation in Tensorflow

안정적(stable) 텐서플로를 사용해서는 단지 배치 정규화만 구현할 수 있다. 다른 것은 Tensorflow add-on을 설치해야 한다.

pip install -q --no-deps tensorflow-addons~=0.7

모델을 생성하고 각 정규화 레이어를 추가해보자.

import tensorflow as tf
import tensorflow_addons as tfa

#Batch Normalization
model.add(tf.keras.layers.BatchNormalization())

#Group Normalization
model.add(tf.keras.layers.Conv2D(32, kernel_size=(3, 3), activation='relu'))
model.add(tfa.layers.GroupNormalization(groups=8, axis=3))

#Instance Normalization
model.add(tfa.layers.InstanceNormalization(axis=3, center=True, scale=True, beta_initializer="random_uniform", gamma_initializer="random_uniform"))

#Layer Normalization
model.add(tf.keras.layers.LayerNormalization(axis=1 , center=True , scale=True))

#Weight Normalization
model.add(tfa.layers.WeightNormalization(tf.keras.layers.Conv2D(32, kernel_size=(3, 3), activation='relu')))
그룹 정규화에서 그룹의 수를 할당(assign)할 때 해당 값이 그 당시 표시되는 특성 맵의 수에 대해 환벽하게 나눠지는 수(제수)여야 한다. 위 코드에서는 32로 이것의 제수는 그룹의 수가 32로 나누어지는 것을 나타내기 위해 사용될 수 있다.

간단한 네트워크 구조로 MNIT 데이터셋을 이용하여 정규화를 테스트해보자.

model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Conv2D(16, kernel_size=(3, 3), activation='relu', input_shape=(28, 28, 1)))
model.add(tf.keras.layers.Conv2D(32, kernel_size=(3, 3), activation='relu'))
#ADD a normalization layer here
model.add(tf.keras.layers.Conv2D(32, kernel_size=(3, 3), activation='relu'))
#ADD a normalization layer here
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(128, activation='relu'))
model.add(tf.keras.layers.Dropout(0.2))
model.add(tf.keras.layers.Dense(10, activation='softmax'))
model.compile(loss=tf.keras.losses.categorical_crossentropy,
optimizer='adam', metrics=['accuracy'])
128, 64, 32, 16, 8 크기의 5가지 배치 사이즈로 모든 정규화에 대해 적용해 본 결과는 아래와 같다.

데이터셋 편향(bias)와 행운 같은 차이들 때문에 결과에 대해 깊이 들여다 보진 않는다. 훈련을 계속 반복하면 다른 결과가 나올 수도 있다.

만약 더 자세한 정보 또는 더 많은 정규화 기술을 알고 싶다면, 다음 \[[링크](http://mlexplained.com/2018/11/30/an-overview-of-normalization-methods-in-deep-learning/)\]를 참고하자.  

만약 네트워크를 더 개선하기를 원한다면 다음 \[[링크](https://towardsdatascience.com/beyond-the-standard-cnn-in-tensorflow-2-a7562d25ca2d)\]를 참고하자.

2020.06.19 수정

반응형

+ Recent posts