배치 정규화
배치 정규화(Batch Normalization)를 이용하면 vanishing gradient와 exploding gradient 문제를 해결할 수 있다.
각 층에서 활성화 함수를 통과하기 전이나 후에 연산을 하나 추가하는 것으로 처리할 수 있다. 각 연산은 다음과 같은 과정을 수행한다.
- 입력을 원점에 맞추고 정규화한다.
- 각 층에서 두 개의 새로운 파라미터로 결괏값의 스케일을 조정하고 이동시킨다. 새로운 파라미터 중 하나는 스케일 조정, 하나는 이동에 사용된다.
신경망의 첫 번째 층으로 배치 정규화를 추가하면 StandardScaler나 Normalization 층이 필요하지 않다. 배치 정규화 층이 이 역할을 대신하기 때문이다.
배치 정규화에서는 현재의 미니배치에서 입력의 평균과 표준 편차를 평가한다. 알고리즘은 다음과 같다.
- $\mu_B = \frac{1}{m_B} \displaystyle \sum_{i=1}^{m_B}{x^{(i)}}$
- $\sigma_{B}^2 = \frac{1}{m_B} \displaystyle \sum_{i=1}^{m_B}{(x^{(i)} - \mu_B)^2}$
- $\hat{x}^{(i)} = \frac{x^{(i)} - \mu_B}{\sqrt{\sigma_{B}^2 + \epsilon}}$
- $z^{(i)} = \gamma \otimes \hat{x}^{(i)} + \beta$
- 작은 첨자 B는 모두 미니 배치에 대한 것이다.
- $\epsilon$ 은 분모가 0이 되는 것을 막기 위한 작은 수이다.
- $\hat{x}^{(i)}$ 는 평균이 0이고 정규화된 샘플 i의 입력이다.
- $\gamma$: 층의 출력 스케일 파라미터 벡터.
- $\beta$: 층의 출력 이동 파라미터 벡터.
- $z^{(i)}$: 배치 정규화 연산의 출력. 입력의 스케일을 조정하고 이동시킨 결과.
훈련 시에는 위 과정대로 진행할 수 있지만 테스트 시에는 어떻게 할까? 샘플의 배치가 아니라 하나의 샘플마다 하나의 예측을 만들어야 하기 때문에 간단한 문제는 아니다. 다음과 같은 방법을 사용할 수 있다.
- 훈련이 끝난 후 전체 train set을 신경망에 통과시켜 배치 정규화 층의 각 입력에 대한 평균과 표준편차 계산. 이 결과를 대신 사용한다.
- (대부분 사용하는 방법) 층의 입력 평균과 표준 편차의 이동 평균을 사용해 훈련하는 동안 최종 통계를 추정.
2번의 방법을 사용하면 최종적으로 배치 정규화에서는 4개의 파라미터가 추가되는 것이다.
- $\gamma$: 층의 출력 스케일 파라미터 벡터.
- $\beta$: 층의 출력 이동 파라미터 벡터.
- $\mu$: 최종 입력 평균 벡터.
- $\sigma$: 최종 입력 표준 편차 벡터.
마지막 2개는 훈련하는 동안 추정되지만, 실제 사용되는 것은 훈련이 끝난 다음이다.
배치 정규화는 훈련의 속도를 크게 향상시켜주며, 규제와 비슷한 역할을 하여 다른 규제 방법의 필요성을 줄여준다.
물론 단점도 있다. 모델의 복잡도가 늘어나고, 추가적으로 필요한 계산도 생기므로 실행 시간 면에서도 손해이다. 하지만 훈련이 끝난 뒤, 이전 층과 배치 정규화 층을 합쳐 실행 속도를 줄일 수 있다.
배치 정규화 구현은 다음과 같이 한다.
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=[28, 28]),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Dense(300, activation="relu",
kernel_initializer='he_normal'),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Dense(100, activation="relu"),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Dense(10, activation="softmax")
])
권장하지는 않지만, 다음과 같이 활성화 함수 이후에 배치 정규화를 할 수도 있다.
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=[28, 28]),
tf.keras.layers.Dense(300, kernel_initializer='he_normal', use_bias=False),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Activation('relu'),
tf.keras.layers.Dense(100, kernel_initializer='he_normal', use_bias=False),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Activation('relu'),
tf.keras.layers.Dense(10, activation='softmax')
])
BatchNormalization
클래스에서 중요한 하이퍼파라미터로는 momentum
과 axis
가 있다.
momentum
: 배치 정규화 층이 지수 이동 평균을 업데이트 할 때 사용. 새로운 값과 이전 값의 비율을 결정한다.axis
: 정규화할 축을 결정.
심층 신경망, 심층 합성곱 신경망에서는 배치 정규화를 거의 당연시하기 때문에 그림에서도 빠져 있는 경우가 많다.
Gradient Clipping
Gradient clipping은 gradient가 일정 값 이상이 되면 gradient를 잘라내는 것을 말한다. 이를 통해 exploding gradient를 방지할 수 있다.
optimizer = tf.keras.optimizers.SGD(clipvalue=1.0)
model.compile(loss="sparse_categorical_crossentropy", optimizer=optimizer)
위와 같이 clipvalue=1.0
로 지정하게 되면 gradient vector의 모든 요소를 -1.0과 1.0 사이로 잘라낸다. 이를 잘 활용하면 gradient vector의 방향을 바꾸어낼 수도 있다(e.g. [0.9, 100.0] -> [0.9, 1.0]).
방향을 바꾸는게 싫다면 clipnorm
으로 지정하자.
Transfer learning
전이 학습(transfer learning)은 비슷한 유형의 문제 해결에 사용된 신경망을 가져오는 것을 말한다. 훈련 속도를 높일 뿐 아니라 필요한 데이터의 양도 크게 줄일 수 있다.
당연히 다른 문제에서 사용한 출력층이 내가 해결하고자 하는 문제와는 맞지 않을 가능성이 크기 때문에, 보통의 경우 출력층은 바꾸어 준다. 또한, 상위 은닉 층은 하위 은닉 층보다 덜 유용하므로(상위 층이 고수준 특성을 학습하기 때문), 하위 은닉층만 가져오는 경우도 많다.
보통 전이 학습은 다음과 같은 과정으로 진행된다.
- 재사용할 층을 모두 동결한다. 이는 경사 하강법으로 가중치가 바뀌지 않도록 한다는 의미이다.
- 모델을 훈련하고 평가한다.
- 결과에 따라 맨 위 한 두 개 층의 동결을 해제하고 다시 평가한다. 이때, 학습률을 줄이는 것이 도움이 된다.
- 여전히 성능이 좋지 않다면 상위 한 두 개 층을 아예 제거하고 남은 은닉 층을 동결한다.
- 적절한 재사용 은닉 층 수를 찾을 때까지 3~4를 반복한다.
keras에서 전이 학습을 하는 자세한 과정은 코드를 참고하자. (기존 신경망에는 변화가 없도록) 신경망을 clone하는 과정, 동결, 동결 해제 등의 방법을 눈여겨 보자.
비지도 사전 훈련
레이블된 훈련 데이터가 많이 없다면 비지도 사전 훈련(Unsupervised Pretraining)을 할 수 있다.
- 오토 인코더(autoencoder)나 GAN 같은 비지도 학습 모델을 훈련한다.
- 그 하위 층을 재사용하여 알맞은 출력 층을 추가한다.
- 지도 학습을 사용해 레이블된 샘플로 신경망을 미세 튜닝한다.
별도의 출처 표시가 있는 이미지를 제외한 모든 이미지는 강의자료에서 발췌하였음을 밝힙니다.
댓글남기기