데이터 정규화 및 웨이트 초기화

  • weight의 초깃값이 신경망 모델의 학습에 영향을 미치는데, 초깃값을 어떻게 설정해야 좋을까?
  • weight에 관해 생각해보기 위해 입력 데이터를 '깔끔하게' 정리를 해보자.
  • 다양한 입력 데이터가 일정한 범위에 들어가도록 전처리를 해보자. 가장 좋은 방법은 이 범위를 \(0~1\) 사이의 값을 갖도록 하는 것이다.
  • 예를 들어 MNIST 데이터의 경우 데이터가 \(0\)에서 \(255\)까지의 gray scale 값을 갖기 때문에 다음과 같이 코드를 작성하면 입력 데이터의 값이 모두 \(0\)부터 \(1\) 사이의 값을 갖게 된다.
X = X / 255


  • 위의 코드를 다른 모든 데이터에도 적용이 가능하도록 일반화하면 다음과 같다.
X = X / X.max()


  • 위의 과정처럼 데이터가 일정한 범위 안에 들어가게 해서 그 다음 처리를 원할하게 이루어지도록 하는 것을 정규화(normalization)이라고 한다.
  • 데이터의 분포를 생각하면 데이터의 평균이 \(0\)이 되도록 정규화하는 것이 좋다. 이 과정을 코드로 바꾸면 다음과 같다.
X = X / X.max()
X = X - X.mean(axis=1).reshape(len(X), 1)


  • 데이터를 정규화했을 때 데이터의 분포가 한쪽으로 치우지지 않는다면 weight의 성분은 양수값과 음수값을 모두 갖게 될 것이다. 이 때 weight의 값이 한쪽으로 치우지지 않는다면 양수와 음수가 거의 반반으로 비슷하게 분포할 것이다. 따라서 weight의 성분을 모두 $0$으로 초기화하는 것을 가장 먼저 생각해볼 수 있다.
    • weight의 성분을 모두 같도록 초기화하면 오차역전파식을 사용했을 때 경사값도 같아져버리므로 weight 값이 제대로 갱신되지 못하기 때문에 \(0\)에 가까운 난수로 초기화를 해야한다.
    • 지금까지 weight의 값을 정규분포를 사용해 초기화한 이유는 평균이 \(\mu=0\)에 가까운 난수를 얻기 위함이다. 또한 표준편차 \(\sigma\)가 작을수록 weight의 성분들은 \(0\)에 가까워져 평균도 \(0\)에 가깝기 때문에 좋다. 따라서 이를 위하여 np.random.normal(scale=0.01, size=shape) 함수를 사용하는 것이다.
  • 단순히 표준편차 \(\sigma\)를 작게 한다고 좋아지는 것은 아니다. 초깃값이 너무 작으면 weight가 계수로 곱해지는 경사값도 너무 작아져 학습이 제대로 진행되지 않는 문제가 발생한다.
    • ReLU는 \(\mathbb{x}=0\) 부근에서도 경사가 소실되지 않는 성질을 지난 활성화 함수이기 때문에 표준편차를 \(\sigma=0.01\)과 같이 작은 값으로 잡아야 학습이 잘 진행되는 경향이 있다.
  • 문제 해결을 위해 표준편차가 \(\sigma=1.0\)인 표준정규분포를 전제로 여기에 적절한 계수를 곱해서 좋은 초깃값을 생성하는 방법을 사용하는데, a*np.random.normal(scale=0.01, size=shape)에서 a에 어떤 값을 줘야 하는 것인가이다.
    • 주의할 점은 입력 데이터의 차원 수가 높을 수록 (표준편차의 값이 \(1.0\)이기 때문에) 생성되는 weight의 성분 값들이 서로 흩어지기 쉬워진다는 것이다. 따라서 weight를 초기화할 때 이 흩어짐을 억제할 수 있는 방법이 필요하다.


웨이트 성분값들의 흩어짐을 막기 위한 방법

  • 입력 데이터 \(\mathbb{x}\)가 \(n\)차원이고, weight가 \(W\)일 때, 활성화되기 전의 값을 \(\mathbb{p}\)라고 하면 \(\mathbb{p}\)의 각 성분 \(p_j\)는 식 \((12.1)\)과 같이 나타낼 수 있다.

\begin{align}p_j = \sum_{i=1}^nw_{j_i}x_i \tag{12.1}\end{align}

  • 이 때 \(E[\cdot]\)가 기대값(평균)이라 하고, \(Var[\cdot]\)를 분산이라고 하면 식 \((12.2)\)가 성립한다.

\begin{align} Var[X]=E[X^2]-(E[X])^2 \tag{12.2} \end{align}

  • \(p_j\)의 분산은 다음과 같다.

\begin{align}Var\left[p_j\right] &= Var\left[\sum_{i=1}^nw_{j_i}x_i\right]\tag{12.3}\\&= \sum_{i=1}^n Var\left[w_{j_i}x_i\right]\tag{12.4}\\&= \sum_{i=1}^n \left\{E \left[ \left(w_{j_i}x_i\right)^2 \right] - \left( E \left[ w_{j_i}x_i \right] \right)^2 \right\}\quad(\because\,\,(12.2))\tag{12.5}\\&= \sum_{i=1}^n \left\{E \left[ w_{j_i}^2x_i^2 \right] - \left( E \left[ w_{j_i} \right] \cdot E \left[x_i \right]\right)^2 \right\}\tag{12.6}\\&= \sum_{i=1}^n \left\{E \left[ w_{j_i}^2\right] \cdot E \left[ x_i^2 \right] - \left( E \left[ w_{j_i} \right] \right)^2 \cdot \left(E \left[x_i \right]\right)^2 \right\}\tag{12.7}\end{align}

  • 이제 \(E [ w_{j_i}^2]\)와 \(E [ x_i^2 ]\)를 따로 계산하면 다음과 같다.

\begin{align}E \Big[ w_{j_i}^2\Big] &= Var\Big[w_{j_i}\Big] + \Big(E \Big[ w_{j_i}\Big]\Big)^2 \tag{12.8}\end{align}

\begin{align}E \Big[ x_i^2 \Big] &= Var\Big[x_i\Big] + \Big(E \Big[ x_i\Big]\Big)^2\tag{12.9}\end{align}


  • 식 \((12.8)\)과 식 \((12.9)\)의 곱을 계산하면 식 \((12.10)\)과 같다.

\begin{align}E \Big[ w_{j_i}^2\Big] \cdot E \Big[ x_i^2 \Big] &= \bigg(Var\Big[w_{j_i}\Big] + \Big(E \Big[ w_{j_i}\Big]\Big)^2\bigg) \cdot \bigg(Var\Big[x_i\Big] + \Big(E \Big[ x_i\Big]\Big)^2\bigg) \tag{12.10}\\&=Var\Big[w_{j_i}\Big]Var\Big[x_i\Big] + Var\Big[w_{j_i}\Big]\Big(E \Big[ x_i\Big]\Big)^2 + \Big(E \Big[ w_{j_i}\Big]\Big)^2 Var\Big[x_i\Big] +  \Big(E \Big[ w_{j_i}\Big]\Big)^2\Big( E \Big[ x_i \Big] \Big)^2 \tag{12.11}\end{align}


  • 식 \((12.11)\)을 식 \((12.9)\)에 대입하면 식 \((12.11)\)과 식 \((12.9)\)의 마지막 항들이 소거되어 식 \((12.12)\)가 된다.

\begin{align}Var\big[p_j\big] &= \sum_{i=1}^n \Bigg\{ Var\Big[w_{j_i}\Big]Var\Big[x_i\Big] + Var\Big[w_{j_i}\Big]\Big(E \Big[ x_i\Big]\Big)^2 + \Big(E \Big[ w_{j_i}\Big]\Big)^2 Var\Big[x_i\Big] \Bigg\} \tag{12.12}\end{align}


  • 이제 입력 데이터가 정규화가 되어 있다면 \(E[x_i]=0\)이며, 또한 weight가 이상적으로 정규분포를 따른다고 가정하면 \(E[w_{j_i}]=0\)이기 때문에 식 \((12.12)\)는 식 \((12.15)\)가 된다.

\begin{align}Var\big[p_j\big] &= \sum_{i=1}^n \Bigg\{ Var\Big[w_{j_i}\Big]Var\Big[x_i\Big] + Var\Big[w_{j_i}\Big]\Big(\not{E} \Big[ x_i\Big]\Big)^2 + \Big(\not{E} \Big[ w_{j_i}\Big]\Big)^2 Var\Big[x_i\Big]\Bigg\}\tag{12.13}\\ &= \sum_{i=1}^n Var\Big[w_{j_i}\Big]Var\Big[x_i\Big] \tag{12.14}\\ &= n\cdot Var\Big[w_{j_i}\Big]Var\Big[x_i\Big]\tag{12.15}\end{align}


  • 식 \((12.15)\)에 따라 \(\mathbb{p}\)의 분산을 \(\mathbb{x}\)의 분산과 같게 하려면 weight \(W\)의 각 성분의 분산은 \(\frac{1}{n}\)이어야 한다. 즉 \(Var(w_j)=\frac{1}{n}\)이어야 \(Var(W)=\frac{1}{n}\)이기 때문에 식 \((12.15)\)에 의해 \(Var\big[\mathbb{p}\big] = Var\big[\mathbb{x}\big]\)이 된다.


  • \(a\)가 상수이고 \(X\)를 확률변수라고 하면 \(Var[aX]=a^2Var(X)\)이기 때문에 앞에서 언급한 것처럼 a*np.random.normal(scale=0.01, size=shape)에서 a에 어떤 값을 줘야 하는 것인가 하는 문제로 돌아가면 \(a\)는 식 \((12.16)\)이 되어야 한다.

\begin{align} a = \sqrt{\frac{1}{n}} \tag{12.16}\end{align}


  • 따라서 a*np.random.normal(scale=0.01, size=shape)는  다음과 같이 구현해야 한다.
np.sqrt(1.0 / n) * np.random.normal(size=shape)


  • 식 \((12.15)\)를 구하기 위해 몇 가지 가정을 한 상태에서 식을 전개하였다. 이 가정을 바꾸면 초기화하는 방법들을 만들어 낼 수 있다.


LeCun 등 1998년 논문에서 제시하는 초기화 방법

  • Yann LeCun, Leon Bottou, Genevieve B. Orr and Klaus-Robert Müller, Efficient BackProp, Neural Networks: Tricks of the Trade, pp. 9-50, Springer, 1998

  • 이 방법은 정규분포 또는 균등분포를 적용해 초기화하며 균등분포를 적용할 경우의 코드는 다음과 같다.
np.random.uniform(low=np.sqrt(1.0 / n),
                  high=np.sqrt(1.0 / n),
                  size=shape)


  • Keras에서는 kernel_initializer='lecun_uniform'이라는 별칭을 사용할 수 있다.


Glorot and Bengio 2010년 논문에서 제시하는 초기화 방법

  • 이 방법은 정규분포나 균등분포를 사용할 경우 각각의 웨이트 초깃값에 관해 연구한 것으로 코드로 나타내면 균등분포일 경우에는 다음과 같다.
np.random.uniform(low=np.sqrt(6.0 / (n_in + n_out)),
                  high=nq.sqrt(6.0 / (n_in + n_out)),
                  size=shape)


  • 정규분포일 경우에는 다음과 같이 구현하는 것으 좋다고 알려져있다.
np.sqrt(3.0 / (n_in + n_out)) * np.random.normal(size=shape)


  • TensorFlow에서 이 초기화 방법을 사용하려면 tf.contrib.layers.xavier_initializer(uniform=True)를 호출하면 된다.
  • Keras에서는 각각 init='glorot_uniform'init='glorot_normal'을 호출하면 된다.


He 등 2015년 논문에서 제시하는 초기화 방법

  • ReLU를 사용할 경우 어떻게 초기화하는지에 관해 설명하는데 다음과 같이 구현하는 좋다고 주장한다.
np.sqrt(2.0 / n) * np.random.normal(size=shape)


  • Keras에서는 init='he_normal' 사용할 수 있다.



출처 : 정석으로 배우는 딥러닝





'신경망(Neural Network) 스터디' 카테고리의 다른 글

14. 학습 조기 종료  (2) 2018.02.01
13. 학습률 설정  (0) 2018.01.29
11. 학습 과정 시각화  (3) 2018.01.19
10. 신경망 모델 구현 방법  (0) 2018.01.19
9. 오버피팅 문제 해결  (0) 2018.01.19

+ Recent posts