가중치 초기화가 신경망에 미치는 영향
딥러닝 모델에 적합한 가중치 초기화 전략은 무엇일까요? 이 글은 AI 번역본입니다. 오역이 의심되면 댓글로 알려 주세요.
Created on September 15|Last edited on September 15
Comment
이번 글에서 다룰 다양한 방법들을 간단히 미리 비교해 보겠습니다.
신경망은 학습 가능한 파라미터를 가진 함수로 볼 수 있으며, 이 파라미터들은 흔히 가중치와 바이어스라고 부릅니다. 신경망을 학습하기 시작할 때 이러한 파라미터(보통 가중치)는 여러 방식으로 초기화됩니다. 예를 들어 0이나 1 같은 상수값을 쓰기도 하고, 어떤 분포(일반적으로 균등분포나 정규분포)에서 샘플링한 값으로 초기화하기도 하며, 때로는 다음과 같은 더 정교한 방식들을 사용하기도 합니다 Xavier 초기화.
신경망의 성능은 학습을 시작할 때 파라미터를 어떻게 초기화하느냐에 크게 좌우됩니다. 매번 무작위로 초기화하면 재현성이 거의 사라지고 성능도 떨어질 수 있습니다. 반대로 상수값으로 초기화하면 수렴까지 지나치게 오래 걸릴 수 있습니다. 또한 무작위성의 장점을 없애 버려, 경사 기반 학습을 통해 더 빠르게 수렴할 수 있는 신경망의 능력도 약화됩니다. 분명 더 나은 초기화 방법이 필요합니다.
가중치를 신중하게 초기화하면 신경망의 재현성을 높일 뿐 아니라, 이 글에서 살펴보듯 학습 성능도 개선할 수 있습니다. 그럼 시작해 봅시다!
다양한 가중치 초기화 방식
다음과 같은 가중치 초기화 방식들의 효과를 살펴보겠습니다:
- 모든 가중치를 0으로 초기화
- 모든 가중치를 1로 초기화
- 고정된 경계를 가진 균등분포에서 샘플링한 값으로 초기화한 가중치
- 신중하게 조정한 균등분포에서 샘플링한 값으로 초기화한 가중치
- 신중하게 조정한 정규분포에서 샘플링한 값으로 초기화한 가중치
마지막으로, tf.keras의 기본 가중치 초기화 방식이 어떤 영향을 미치는지 살펴보겠습니다.
실험 설정: 데이터와 모델
실험을 빠르고 일관되게 진행하기 위해 데이터셋과 간단한 모델 아키텍처를 고정하겠습니다. 이런 종류의 실험을 시작할 때 제가 가장 선호하는 데이터셋은 FashionMNIST입니다. 우리는 다음과 같은 모델 아키텍처를 사용하겠습니다:

이 모델은 (784,) 형태의 평탄화된 특성 벡터를 입력으로 받아 드롭아웃과 Dense 층을 거친 뒤, FashionMNIST 데이터셋의 10개 클래스에 해당하는 확률을 나타내는 (10,) 형태의 예측 벡터를 출력합니다.
모든 실험에서 사용할 모델 아키텍처는 다음과 같습니다. 손실 함수로는 sparse_categorical_crossentropy를, 옵티마이저로는 Adam을 사용합니다.
방법 1: 모든 가중치를 0으로 초기화
먼저 모든 요소가 0인 가중치 벡터를 모델에 넣고, 10 에포크 동안 학습했을 때 성능이 어떻게 나오는지 확인해 봅시다. tf.keras에서 Dense, Conv2D, LSTM 같은 레이어에는 kernel_initializer와 bias_initializer라는 두 가지 인자가 있습니다. 여기에 미리 정의된 초기화기를 전달하거나 직접 만든 커스텀 초기화기를 넘길 수 있습니다. tf.keras에서 제공하는 모든 초기화기를 정리해 둔 문서를 꼭 확인해 보시길 권합니다.
모델의 모든 Dense 층에 대해 kernel_initializer 인자를 zeros로 설정하면 가중치 벡터를 전부 0으로 초기화할 수 있습니다. 편향은 스칼라이므로, 0으로 설정하더라도 가중치만큼 큰 영향은 없습니다. 코드에서는 다음과 같이 작성합니다:
tf.keras.layers.Dense(256, activation='relu', kernel_initializer=init_scheme, bias_initializer='zeros')
모든 가중치를 0으로 초기화했을 때 모델이 학습하는 방식은 다음과 같습니다 —

학습 손실 대 검증 손실(가중치를 0으로 초기화한 경우)

학습 정확도 대 검증 정확도(가중치를 0으로 초기화한 경우)
위의 두 그래프에서 보듯이 검증 손실과 학습 손실이 크게 벌어지고, 에포크 전��에 걸쳐 검증 정확도는 거의 변하지 않습니다. 이는 모델이 학습에 심각하게 어려움을 겪고 있음을 뜻하며, 주어진 모델 아키텍처를 고려할 때 FashionMNIST 같은 데이터셋에서는 원래 이런 현상이 나타나지 않아야 합니다. 이러한 문제는 주로 모델이 모든 가중치를 0으로 시작했기 때문입니다. 그 결과 역전파로 인한 가중치 업데이트가 대칭성을 깨지 못해, 신호를 제대로 전달하거나 성능을 끌어올리기에 충분히 효과적이지 못한 것입니다.
따라서 우리 모델에는 훨씬 더 나은 시작점, 즉 더 적절한 가중치 초기화가 필요하다고 결론지을 수 있습니다.
방법 2: 모든 가중치를 1로 초기화
tf.keras에서 모델 가중치를 모두 1로 초기화하는 방법은 이전과 거의 같습니다. 0을 1로 바꾸기만 하면 됩니다. 이에 대한 플롯은 아래와 같습니다.

학습 손실 대 검증 손실(가중치를 1로 초기화한 경우)

학습 정확도 대 검증 정확도(가중치를 1로 초기화한 경우)
손실 감소는 분명 더 좋아 보입니다. 모든 값을 0으로 설정했을 때보다 훨씬 낫습니다. 학습 정확도와 검증 정확도도 서로 잘 맞아 보였습니다.
연구에 따르면 가중치를 0이나 1 같은 상수가 아니라 무작위 분포에서 샘플링한 값으로 초기화하면 신경망이 더 빠르고 더 잘 학습합니다. 이렇게 도입된 무작위성은 경사 기반 최적화에 매우 적합할 뿐 아니라, 어떤 가중치를 업데이트해야 하는지 네트워크가 더 잘 판단하도록 도와줍니다. 직관적으로, 가중치를 일정한 값으로 초기화하면 초기 순전파 동안 각 층의 출력이 사실상 모두 같아져서, 네트워크가 어떤 가중치를 업데이트해야 하는지 파악하기가 매우 어려워집니다.
이제 균등 분포에서 샘플링한 값으로 모델의 가중치를 초기화하면 어떻게 되는지 살펴보겠습니다.
방법 3: 균등 분포에서 샘플링한 값으로 가중치 초기화
수학적 관점에서 보면, 신경망은 결국 여러 함수가 차례로 합성된 구조입니다. 각 함수에서는 보통 입력 벡터에 가중치 벡터를 곱하고, 거기에 편향 항을 더합니다(브로드캐스팅을 떠올리면 됩니다). 그런 다음 최종 벡터를 활성화 함수에 통과시키고, 그 결과를 다음 단계로 전달합니다.
이상적으로는 가중치 벡터의 값이 입력 벡터의 정보 손실을 일으키지 않도록 설정되어야 합니다. 결국 우리는 가중치 벡터를 입력 벡터와 곱하므로 매우 신중해야 합니다. 따라서 가중치 벡터의 값을 가능한 한 작게 유지하되, 너무 작아서 수치적 불안정을 유발하지는 않도록 하는 것이 흔히 좋은 실무 관행입니다.
앞선 실험에서 모델을 상수 값으로 초기화하는 것은 좋지 않다는 것을 확인했습니다. 따라서 이번에는 [0, 1] 범위의 서로 다른 작은 값들로 초기화해 보겠습니다. 이는 다음과 같이 값들을 샘플링하여 수행할 수 있습니다. 균등 분포균등 분포는 다음과 같습니다.

[-5, 5] 범위의 균등 분포
균등 분포에는 이런 함정이 있습니다:
균등 분포에서 추출되는 값들은 모두 동일한 확률로 샘플링됩니다.
tf.keras의 Dense 레이어를 균등 분포로 초기화하는 작업은 앞선 두 방식보다 조금 더 손이 갑니다. 우리는 다음을 활용합니다 tf.keras.initializers.RandomUniform(minval=min_val, maxval=max_val, seed=seed) 여기서는 해당 클래스를 사용합니다. 이 경우 minval에는 0, maxval에는 1을 지정하면 됩니다. seed는 원하는 임의의 정수를 사용할 수 있습니다. 성능을 확인해 봅시다!

훈련 손실과 검증 손실(균등 분포로 초기화한 가중치)

훈련 정확도와 검증 정확도(균등 분포로 초기화한 가중치)
손실은 이전 실험(가중치를 모두 1로 초기화한 경우)과 거의 비슷하지만, 정확도는 상당히 크게 향상되었습니다. 아래 그래프를 보면 비교가 더 쉬워집니다.

정확도 트레이드오프 1부
이전 실험에서 보았듯이, 신경망의 가중치를 초기화할 때 약간의 무작위성을 주면 분명히 도움이 됩니다. 그렇다면 이 무작위성을 통제하면서 모델에 의미 있는 정보를 제공할 수는 없을까요? 우리가 모델에 넣을 입력에 대한 정보를 일부 전달하고, 그에 따라 가중치가 어느 정도 그 정보에 의존하도록 만들 수 있다면 어떻게 될까요?
할 수 있습니다! 다음 규칙이 이를 돕습니다:

이 규칙은 Udacity의 Weight Initialization 강의(Deep Learning Nanodegree의 일부)에서 가져왔습니다.
방법 4: 균등 분포에서 신중히 조정한 범위로 샘플링해 가중치 초기화
그래서 [0, 1] 범위의 균등 분포에서 값을 샘플링하는 대신, 범위를 [-y, y]로 바꾸겠습니다. tf.keras에서 이를 구현하는 방법은 여러 가지가 있지만, 아래 방법이 가장 커스터마이즈하기 쉽고 가독성도 좋다고 생각합니다.
# iterate over the layers of a given modelfor layer in model.layers:# check if the layer is of type Denseif isinstance(layer, tf.keras.layers.Dense):# shapes are important for matrix multshape = (layer.weights[0].shape[0], layer.weights[0].shape[1])# determine the `y` valuey = 1.0/np.sqrt(shape[0])# sample the values and assign them as weightsrule_weights = np.random.uniform(-y, y, shape)layer.weights[0] = rule_weights # weightslayer.weights[1] = 0 # bias
이제, 성능을 확인해 봅시다.

훈련 손실 대 검증 손실(규칙에 따른 균등 분포 가중치 초기화)

훈련 정확도 대 검증 정확도(규칙에 따른 균등 분포 가중치 초기화)
모델의 학습 거동이 훨씬 개선된 것이 분명히 보입니다. 일반화가 잘되기 시작했을 뿐 아니라 정확도도 크게 향상되었습니다.
이제 마지막 실험으로, 표준편차를 y로 설정한 정규분포에서 값을 샘플링해 보겠습니다.
방법 5: 신중히 조정한 정규분포에서 샘플링해 가중치 초기화
왜부터 시작해 봅시다. 여기서 왜 정규분포를 사용할까요? 앞서, 더 작은 가중치 값이 네트워크가 잘 학습하는 데 유리할 수 있다고 언급했습니다. 초기 가중치를 0에 가깝게 유지하려면, 균등분포보다 정규분포가 더 적합합니다. 균등분포에서는 모든 값이 동일한 확률로 샘플링되지만, 정규분포는 그렇지 않기 때문입니다. 평균을 0으로 두고 표준편차를 y로 설정한 정규분포에서 샘플링하겠습니다.
아래 그림(정규분포를 모사한)을 보면 대부분의 값이 평균 부근에 집중되어 있음을 알 수 있습니다. 우리의 경우 평균이 0이므로, 의도한 대로 동작할 가능성이 있습니다.

표본 정규분포
이 방식으로 가중치를 초기화하는 코드도 거의 동일합니다. 균등 분포 규칙을 정규분포로 바꾸면 됩니다.
# iterate over the layers of a given modelfor layer in model.layers:# check if the layer is of type Denseif isinstance(layer, tf.keras.layers.Dense):# shapes are important for matrix multshape = (layer.weights[0].shape[0], layer.weights[0].shape[1])# determine the `y` valuey = 1.0/np.sqrt(shape[0])# sample the values and assign them as weightsrule_weights = np.random.normal(0, y, shape)layer.weights[0] = rule_weights # weightslayer.weights[1] = 0
성과는 다음과 같습니다.

훈련 손실 vs. 검증 손실(규칙 기반 정규분포로 가중치 초기화)

훈련 정확도 vs. 검증 정확도(규칙 기반 정규분포로 가중치 초기화)
이 방식과 이전 방식의 성능 차이는 크지 않습니다. 비교를 위해 더 보기 편한 비교 그래프를 확인해 봅시다:

손실 상충관계

여기서는 비교가 매우 어렵습니다. 또한 우리 네트워크가 충분히 깊지 않아, 정규분포에서 샘플링하는 것이 신경망에 유익한지 제대로 비교하기 어렵다는 점도 고려해야 합니다. 이 부분은 주말에 재미 삼아 직접 실험해 보시길 권합니다.
다음 섹션에서는 앞서 살펴본 몇 가지 방법을 적용해 보고, 네트워크를 학습시키면서 그에 따라 가중치가 어떻게 달라지는지 비교하겠습니다.
신중한 초기화가 학습에 미치는 영향
이제 서로 다른 초기화 방법이 학습 과정에서 네트워크의 파라미터에 어떤 영향을 미치는지 살펴보겠습니다. 먼저 [0, 1] 범위를 사용하는 균등 분포 초기화를 보겠습니다. TensorBoard(머신러닝 모델을 시각화하고 디버깅하기 위해 TensorFlow 팀이 제공하는 도구)는 모델이 학습한 파라미터를 히스토그램과 분포로 시각화할 수 있습니다. 이 글에서는 히스토그램에 집중하겠습니다.

히스토그램은 값의 구간을 나누어 각 구간에서의 발생 빈도를 나타냅니다. 위 그림에서 보듯이, 서로 다른 레이어의 가중치 대부분이 [0, 1] 범위 전반에 고르게 분포해 있습니다.
다음은 균등 분포로 초기화하되, 다음 규칙을 적용한 우리 네트워크의 히스토그램입니다:

균등 분포로 초기화하되 해당 방식(레시피)을 적용한 우리 네트워크의 학습된 파라미터 히스토그램.
제한된 균등 분포로 네트워크를 초기화했을 때 가중치 분포의 산포가 줄고 대부분의 값이 0에 더 가까워졌음을 분명히 확인할 수 있습니다. 이는 우리가 의도했던 바와 같습니다.
이번 관찰을 우리가 논의한 다른 초기화 방법에도 직접 적용해 보시길 권합니다. Weights & Biases는 TensorFlow 이벤트 파일을 손쉽게 동기화해, Weights & Biases 실행 페이지에서 바로 TensorBoard 인스턴스를 호스팅할 수 있게 해줍니다. 이 글에서는 해당 코드까지는 다루지 않지만, 관심이 있다면 다음을 확인해 보세요 Colab 노트북 →.
몇 가지 팁과 마무리 생각
끝까지 함께해 주셔서 감사합니다. 신경망의 가중치 초기화는 학습 성능에 큰 영향을 미치기 때문에 개인적으로도 아주 흥미로운 주제입니다. 재미 삼아 tf.keras에서 Dense 레이어의 기본 이니셜라이저가 무엇인지 확인해 보고, 이 글에 제시된 결과와 비교해 보셔도 좋겠습니다.
이제 신경망이 잘 학습되지 않는 이유를 체계적으로 점검할 수 있는 사고방식을 갖추셨을 것입니다. 실제로 원인은 매우 다양하지만, 가중치 초기화는 그중 확실한 요인입니다. 이제 실험해 볼 만한 기본 초기화 기법들의 목록을 갖게 되셨습니다.
또한 이 주제를 더 깊이 공부하고 싶다면 참고할 만한 훌륭한 자료들을 공유하고자 합니다. 이 연구 분야는 다음과 같은 기념비적 논문으로 널리 알려지기 시작했습니다. Xavier 등의 “심층 피드포워드 신경망 학습의 어려움 이해”그 후 Kaiming 등의 논문에서 매우 체계적으로 연구되었습니다 정류 함수의 심층 탐구: ImageNet 분류에서 인간 수준을 뛰어넘는 성능같은 해에 Dmytro 등은 “All you need is a good init”라는 논문을 발표하며 Layer-wise Sequential Unit Variance(LSUV)라는 매우 단순하지만 효과적인 가중치 초기화 기법을 제안했습니다. LSUV는 더 깊은 아키텍처에서 탁월한 성능 향상을 보여 주었고, 실무자들 사이에서 손쉽게 선호되는 선택지가 되었습니다. 또한 Adam 등의 논문에서는 가중치 비민감 신경망에 대한 연구도 제시되었습니다. 가중치 비민감 신경망 하지만 이전 기법들만큼의 주목을 받지는 못하고 있습니다.
가중치 초기화 방법과 활성화 함수의 올바른 조합을 선택하는 문제도 중요한 연구 주제이며, 이에 관해 읽어보실 것을 강력히 추천합니다. DeepLearning.AI의 이 아티클 관심이 있으시다면 자세히 살펴보세요.
저는 Jeremy Howard와 그의 팀에게 깊이 감사드립니다 fast.ai fast.ai의 강의였기 때문입니다 기초부터 배우는 딥러닝 (Jeremy가 직접 진행한) 그 강의가 저의 가중치 초기화 주제에 대한 관심을 불러일으켰습니다. 아직 강의를 보지 않으셨다면, 시간을 내어 꼭 확인해 보세요.
이 글을 통해 가중치 초기화 방법이 신경망 학습에서 얼마나 중요한 역할을 하는지 감을 잡으셨길 바랍니다. 여러분의 맞춤형 신경망에서도 성능 향상에 도움이 되길 기대합니다.
Add a comment
