[Computer Vision] 3(2). 훈련 프로세스 개선

6 minute read


훈련 프로세스 개선

네트워크 아키텍처만 개선되어 온 것은 아니다. 네트워크 훈련 방법도 진화하여 수렴의 신뢰도와 속도가 개선되었다.

이제부터는 경사 하강 알고리즘의 단점을 해결하는 동시에 과적합을 피할 몇 가지 방법에 대해 알아본다.


현대 네트워크 최적화 기법


경사 하강법의 까다로운 점

경사 하강법은 학습률과 손실함수의 기울기를 곱하여 그 경사를 최소화하는 방향으로 가중치 초기화를 진행한다. 이 때 학습률이 매우 중요하다.


1. 훈련 속도와 트레이드 오프

학습률을 과도하게 낮게 잡으면 수렴하는데 오래 걸리고, 과도하게 높게 잡으면 극솟값을 지나쳐 버릴 수 있다. 이러한 학습률 조정 문제를 해결하는 유명한 방법으로 학습률을 큰 값으로 시작하여 세대가 넘어갈 때마다 학습률을 줄이는 학습률 감소 방법이 있다. 지금의 텐서플로는 더 진화된 형태의 학습률 스케줄러적응형 학습률을 적용하는 최적화기를 제공한다.

2. 준최적 극솟값

경사 하강법은 ‘더 나은’ 최솟값이 가까이 있더라도 최적이 아닌 극솟값으로 귀결될 수 있다.

3. 이기종 매개변수를 위한 단일 초매개변수

전통적인 경사 하강법이 모든 매개변수에 대해 동일한 학습률을 적용하는 데 반해, 실제로는 모든 변수가 변화에 동일한 민감도를 갖지 않으며 반복할 때마다 모든 변수가 손실에 영향을 주지도 않는다. 결정적인 매개변수를 좀 더 신중하게 업데이트 하기 위해 매개변수 단위로 학습률을 다르게 적용하고, 네트워크 예측에 충분히 기여하지 않는 매개변수는 돔 더 과감하게 업데이트하는 것이 효과적일 수 있다.


고급 최적화 기법


모멘텀 알고리즘

모멘텀 알고리즘은 SGD을 기반으로 모멘텀(가속도) 개념을 적용하여 매개변수의 업데이트에 이전에 업데이트한 매개변수를 받아 더한다. image-3.png

모멘텀 알고리즘은 다음처럼 SGD의 매개변수를 통해 정의된다.

# lr = SGD의 계수, momentum = 모멘텀의 계수
# decay = 각 업데이트에 대한 학습률 감소, 
optimizer = tf.optimizers.SGD(lr=0.01, momentum=0.9, 
                              decay = 0.0, nesterov=False)

네스테로프 알고리즘

위의 optimizer에서 nesterov=True로 지정하면 네스테로프 알고리즘이 된다.

모멘텀 알고리즘의 문제점은 네트워크가 손실 최솟값에 다가갈 때 누적 모멘텀이 일반적으로 너무 높아서 타깃 최솟값을 놓치거나 그 주변을 왔다갔다 할 수 있다는 것이다.

네스테로프 가속 경사(NAG)는 최적화기가 미리 경사를 확인할 수 있게 해 경사가 가팔라지면 속도를 늦춰야 한다는 것을 ‘알게 하자’라는 아이디어이다. image-2.png

Ada 군

Adagrad, Adadelta, Adam 등은 각 뉴런의 민감도 및 활성화 빈도에 따라 학습률을 조정하는 아이디어에 몇 가지 반복과 변형을 준 알고리즘이다.

  • Adagrad: 일반적으로 발견할 수 있는 특징과 연결된 매개변수에 대해서는 자동으로 학습률을 더 빠르게 감소시키고, 드물게 발견되는 특징은 더 천천히 감소시킨다.
  • Adadelta: ‘Adagrad’의 반복 시마다 학습률을 감소시키면 어느 시점에는 학습률이 너무 작아질 수 있다는 문제점을 매개변수마다 학습률을 나누기 위해 사용되는 요인을 지속적으로 확인함으로써 방지한다.
  • Adam: 매개변수마다 학습률을 조정하기 위해 이전 업데이트 항을 저장할 뿐 아니라 과거 모멘텀 값을 기록한다. 따라서 이 기법은 종종 ‘Adadelta’와 ‘Momentum’의 혼합형으로 이해되기도 한다. Nadam은 ‘Adadelta’와 ‘NAG’로부터 상속받은 최적화기이다.

어느 최적화기가 최선인지에 대한 답은 없지만, 부족한 데이터에서의 효과성 때문에 일반적으로 ‘Adam’을 선호한다.

RMSProp

RMSProp은 ‘Adagrad’의 학습률이 너무 작아지는 문제를 해결하기 위해 지수 이동 평균 개념을 활용하여 문제를 방지한다.

RMSProp은 대체로 순환 신경망에 사용하기 적절한 것으로 간주된다.



정규화 기법


훈련 데이터 뿐 아니라 테스트 데이터에서도 좋은 성능을 내려면 (네트워크 일반화에 성공하려면) 풍부한 훈련 집합잘 정의된 아키텍처가 핵심이다.

그렇지만 이와 별개로 과적합을 피하기 위한 최적화 단계를 정교화하는 프로세스인 정규화를 위한 기법들도 수년간 개발되어 왔다.


조기 중단

신경망은 동일한 작은 훈련 샘플 집합에 대해 너무 여러 번 반복하면 과적합되기 시작한다.

훈련 과정의 중단 여부는 ‘교차 검증’을 이용하는데, 검증 데이터셋을 최적화기에 제공함으로써 네트워크가 직접 최적화되지 않았던 이미지에서 모델 성능을 측정할 수 있도록 한다.

이 때 훈련을 조기에 중단한다고 판단을 내리는 것을 조기 중단이라고 한다.

조기 중단 과정(모니터링, 조기 중단, 최적 가중치의 복원)은 케라스의 ‘콜백’ 중 하나인 tf.keras.callbacks.EarlyStop에서 자동으로 처리한다.

  • 텐서플로와 케라스 구현
tf.keras.callbacks.EarlyStopping(patience=3, monitor='val_loss')


L1, L2 정규화 (가중치 정규화)

과적합을 방지하는 또 다른 방법으로는 훈련 목표 중 하나로 정규화를 포함시키기 위해 손실 함수를 수정하는 것이다.

L2 정규화(릿지 정규화)는 네트워크가 매개변수의 값의 제곱의 합을 최소화하도록 강제한다. 이 정규화로 인해 최적화 프로세스에서 모든 매개변수 값이 소멸되지만, 제곱 항으로 인해 큰 매개변수는 더 강력하게 처벌된다. 따라서 L2 정규화는 네트워크가 ‘매개변수 값을 낮게 유지해 더 균일하게 분산되게’ 하며, 네트워크가 예측에 영향을 미치는 큰 값을 갖는 적은 수의 매개변수가 개발되는 것을 방지한다.

L1 정규화(라쏘 정규화)는 네트워크가 매개변수의 절댓값의 합을 최소화하도록 한다. L1 정규화를 사용하면 큰 값을 갖는 가중치가 제곱으로 인해 페널티를 부여받지 않는 대신 ‘네트워크가 덜 중요한 특징에 연결된 매개변수를 0으로 축소’한다. 따라서 네트워크가 덜 중요한 특징(예를 들어 데이터셋 노이즈 관련)을 무시함으로써 과적합을 방지한다. 이는 네트워크의 용량이 최소화되어야 하는 경우 유리할 수 있다. KakaoTalk_20210809_214606751

  • 텐서플로와 케라스 구현
from functools import partial

def l2_reg(coef=1e-2): # tf.keras.regularizers.l2() 를 재구현
    return lambda x: tf.reduce_sum(x ** 2) * coef

class ConvWithRegularizers(SimpleConvolutionLayer):
    def __init__(self, num_kernels=32, kernel_size=(3,3), stride=1,
                 kernel_regularizer=l2_reg(), bias_regularizer=None):
        
        super().__init__(num_kernels, kernel_size, stride)
        self.kernel_regularizer = kernel_regularizer
        self.bias_regularizer = bias_regularizer
        
    def build(self, input_shape):
        super().build(input_shape)
        # 정규화 손실을 변수에 추가
        if self.kernel_regularizer is not None:
            # 예를 들어, TF에 호출(반복)마다
            # 'tf.nn.l1_loss(self.kernels)'를 계산하고 저장할 것을 지시
            self.add_loss(partial(self.kernel_regularizer, self.kernels))
        if self.bias_regularizer is not None:
            self.add_loss(partial(self.bias_regularizer, self.bias))
     
    

정규화 손실은 모델이 더 견고한 특징을 학습하게 한다. 다만 이 손실(가중치 정규화 손실)이 주요 훈련 손실보다 우선해서는 안되며, 따라서 정규화 손실에 너무 큰 가중치를 부여하지 않도록(보통 0~1의 값을 부여) 주의해야 한다.

이런 계산 방식은 특히 주요 손실을 평균으로 구하는 방식일 때(MSE, MAE 등) 더 중요하다. 정규화 손실이 주요 손실을 초과하지 않도록 정규화 손실도 매개변수 차원에 대해 평균으로 구하거나 그 계수를 더 감소시켜야 한다.

이런 계층으로 구성된 네트워크의 훈련이 반복될 때마다 다음처럼 정규화 손실을 계산해서 리스트에 추가하고 주요 손실에 더한다.

# 정규화/추가 손실 계층을 포함한 NN 생성
model = Sequential()
model.add(ConvWithRegularizers(6, (5,5), kernel_regularizer=l2_reg()))
model.add(...) # 계층 추가
model.add(Dense(num_classes, activation='softmax'))

# 신경망 훈련 (이전에 정의했던 함수 'training_step()' 과 비교해볼 것)
for epoch in range(epochs):
    for (batch_images, batch_gts) in dataset:
        with tf.GradientTape() as grad_tape:
            loss = tf.losses.sparse_categorical_crossentropy(
                batch_gts, model(batch_images)) # 주요 손실
            loss += sum(model.losses)           # 추가 손실 리스트
        # 결합된 손실의 경사를 구해 역전파
        grads = grad_tape.gradient(loss, model.trainable_variables)
        optimizer.apply_gradients(zip(grads, model.trainable_variables))

사전에 정의된 케라스 계층을 사용할 때는 정규화 항을 추가하기 위해 클래스를 확장하지 않고 간단히 매개변수로 지정할 수 있다.

# 정규화기(예를 들어 L1)를 인스턴스화 함
l1_reg = tf.keras.regularizers.l1(0.01)
# 그런 다음 이 정규화기를 목표 모델의 계층에 매개변수로 전달
model = Sequential()
model.add(Conv2D(6, kernel_size=(5,5), padding='same', activation='relu',
                 input_shape=input_shape, kernel_regularizer=l1_reg))
model.add(...) # 계층 추가
model.fit(...) # 훈련 중 자동으로 정규화 항을 계산에 넣음


드롭 아웃

드롭아웃은 신경망 아키텍처에 직접적으로 영향을 미치는 정규화 기법으로, 훈련이 반복될 때마다 타깃 계층의 일부 뉴런의 연결을 임의로 끊는다. 따라서 이 기법은 초매개변수로 훈련 단계마다 뉴런이 꺼질 확률을 나타내는 비율 p(일반적으로 0.1 ~ 0.5)를 취한다.

인위적인 방식으로 네트워크를 임의로 훼손시킴으로써 이 기법은 견고한 공동의 특징을 학습할 수 있게 해준다. 예를 들어 드롭아웃이 핵심 특징을 담당하는 뉴런을 비활성화 할 경우 네트워크는 동일한 예측에 도달하기 위해 다른 중요한 특징을 알아내야 하며, 이는 예측을 위해 데이터의 중복 표현을 개발하는 효과가 있다.

드롭아웃은 테스트 단계에서는 네트워크에 적용되지 않기 때문에 네트워크의 예측은 부분적인 모델이 제공하는 결과의 조합(평균)으로 볼 수 있다. 따라서 이 정보를 평균하면 네트워크가 과적합되는 것을 방지할 수 있다.

  • 텐서플로 및 케라스 메서드

드롭아웃은 임의로 누락시킬 값을 포함한 텐서를 직접 얻기 위한 tf.nn.dropout(x, rate, …통해 함수로 호출되거나, 신경망 모델에 추가될 수 있는 tf.keras.layers.Dropout()을 통해 계층으로 호출될 수 있다.

드롭아웃 계층은 과적합을 방지할 계층 바로 뒤에 추가되어야 한다.

model = Sequential([ #...
    Dense(120, activation='relu'), 
    Dropout(0.2), #...
])


배치 정규화

배치 정규화 역시 네트워크 아키텍처에 직접 통합된다. 이 연산은 이전 계층의 배치 결과를 취해 ‘정규화(normalize)’, 즉 배치 평균을 빼서 배치 표준편차로 나눈다.

배치가 SGD에서 무작위로 샘플링되어 두 번 이상 같은 가능성은 희박하기 때문에 이는 데이터가 거의 매번 다른 방식으로 정규화된다는 것을 뜻하고, 따라서 네트워크는 이러한 데이터 변화를 다루는 방법을 학습하여 더 일반적이고 견고해진다.

  • 텐서플로 및 케라스 메서드

배치 정규화는 드롭아웃과 마찬가지로 텐서플로에서 함수 tf.nn.batch_normalization()이나 계층 tf.keras.layers.BatchNormalization()으로 적용될 수 있다.

지금까지 살펴본 최적화 기법은 모두 딥러닝에 있어 훌륭한 도구다. 특히 맞춤형 애플리케이션에서 자주 볼 수 있는 균형이 맞지 않거나 부족한 데이터셋에서 CNN을 훈련시킬 때 그렇다.



정리


  • CNN은 합성곱 계층, 풀링 계층, 밀집 계층(과 평면화 계층)으로 이루어진다.
    • 합성곱 계층에서 패딩을 추가하지 않으면 커널의 크기와 스트라이드에 따라 너비와 높이가 작아진다.
  • 경사 하강법의 문제점으로는 훈련 속도-정확도 트레이드 오프, 준최적 극솟값 문제, 각 매개변수의 영향 정도 등이 있다.
    • 최적화 기법으로는 Momentum, NAG(Nesterov Acceleration Gradient), Ada군(Adagrad, Adadelta, Adam), RMS Prop 등이 있다.
  • 정규화는 훈련 과정의 과적합을 피하기 위해 사용된다.
    • 정규화 기법으로는 조기 종료, L1/L2 규제, 드롭아웃, 배치 정규화 등이 있다.
    • L1 규제는 절댓값을 최소화하는 것으로 작은 매개변수(노이즈 등)를 최소화하여 필요없는 매개변수를 버리고, L2 규제는 제곱을 최소화는 것으로 너무 큰 매개변수를 규제하여 매개변수를 고르게 만든다.

Leave a comment