11장. 심층 신경망 훈련하기

심층 신경망 학습 중 발생할 수 있는 문제들과 그에 대한 해결 방안
📌 훈련 속도를 높이는 방법
1. 연결 가중치에 좋은 초기화 전략 사용
2. 좋은 활성화 함수 사용
3. 배치 정규화 사용
4. 사전 훈련된 네트워크의 일부 재사용

1. 그래디언트 소실 및 폭주

1-1. 그래디언트 소실 및 폭주 문제점

  • 그래디언트 소실 : 하위층으로 갈수록 그래디언트가 점점 작아지는 경우
  • 그래디언트 폭주 : 하위층으로 갈수록 그래디언트가 점점 커져 비정상적으로 큰 가중치 갱신

ex) 로지스틱 활성화 함수
입력이 양수나 음수로 커지면 0 or 1로 수렴해 기울기가 0에 가까워진다.
👉🏻 신경망의 위쪽으로 갈수록 분산이 계속 커져 가장 높은 층에서는 활성화 함수가 0 or 1로 수렴해서 전파할 그래디언트가 거의 없고 실제로 아래쪽 층에는 아무것도 도달하지 않는다.

1-2. 해결방법1) 글로럿과 HE초기화

✔️fan-in : 층의 입력 연결 개수
✔️fan-out : 층의 출력 연결 개수

글로럿 초기화(=세이비어 초기화)

  • 각 층의 연결 가중치를 무작위로 초기화
  • 여러 층의 기울기 분산 사이에 균형을 맞춰서 특정 층이 너무 주목 받는 현상을 막는다.
  • 훈련 속도 상승
  • S자 형태의 활성화함수(로지스틱, 소프트맥스)와 함께 사용할 때 좋은 성능(RELU와 함께 사용하면 성능 안좋음)

HE 초기화

  • ReLU 활성화함수에 대한 초기화

    📌 글로럿 초기화 : 로지스틱, 허이퍼볼릭 탄젠트, 소프트맥스 활성화함수와 함께 사용
    📌 HE 초기화 : ReLu 함수와 ReLu함수의 변종들
# 글로럿 초기화
keras.layers.Dense(10, activation='relu', kernel_initializer='he_uniform')

# He초기화
keras.layers.Dense(10, activation='relu', kernel_initializer='he_normal')

# fan_avg 기반 균등 분포 He 초기화
he_avg_init = keras.initializers.VarianceScaling(scale=2., \
						 mode='fan_avg', \
						 distribution='uniform')
keras.layers.Dense(10, activation='sigmoid',\
		   
           kernel_initializer=he_avg_init)

1-3. 해결방법2) 수렴하지 않는 활성화함수

ReLU 함수 : 특정 양숫값에 수렴하지 않는다(장점)
하지만, 죽은 ReLU 문제(훈련하는 동안 일부 뉴런이 0이외의 값을 출력 X) 발생 가능성

ReLU 함수의 변종

  • LeakyReLU
    일반적으로 함수의 기울기(alpha)를 0.01로 설정하여 절대 죽지 않게 만듬
model = keras,models.Sequential([
	[...]
    	keras.layers.Dense(10, kernel_initializer='he_normal'),
    	keras.layers.LeakyReLU(alpha=0.2)
    	[...]
])
  • RReLU
    alpha를 무작위로 선택, 테스트 시에는 평균 사용하여 규제의 역할
  • PReLU
    alpha가 훈련하는 동안 학습(But, 소규모 데이터셋에서는 훈련 세트에 overfitting 위험)
model = keras,models.Sequential([
	[...]
    	keras.layers.Dense(10, kernel_initializer='he_normal'),
    	keras.layers.PReLU()
    	[...]
])
  • ELU
    ReLU와 비슷한 형태로 입력이 0이하일 때, 부드럽게 깍아주면서 평균 출력이 0에 가까워짐
  • SELU
    ELU 활서화 함수의 변종
    모든 은닉층에서 SELU를 사용하면 네트워크가 자기 정규화 된다.
    이때, 네트워크는 일렬로 쌓은 층으로 구성(와이드&딥과 같은 스킵연결 사용 X)
    훈련시 각 층의 출력이 평균 0, 표준편차 1을 유지
layers = keras.layers.Dense(10, activation='selu',
    			    kernel_initializer='lecun_normal')

👉🏻일반적으로 심층 신경망의 은닉층에서,
SELU > ELU > LeakyReLU > ReLU > tanh < Logistic

1-4. 해결방법3) 배치 정규화

배치 단위로 정규화 하는 것
✔️ 배치 : 학습을 하면서 각 layer의 활성화함수의 입력값 또는 출력값에서 정규화

👉🏻Input값이 같더라도 가중치가 달라지면 완전히 다른 값이 되기 때문에 layer에 배치 정규화 과정을 추가하여 가중치 차이를 완화해서 안정적인 학습을 할 수 있도록 한다.

배치 정규화 알고리즘

  • 깊은 네트워크(은닉층이 많은 신경망)에서 주로 사용
  • hidden layer에서 활성화 함수의 입력값 또는 출력값에 연산 추가
  • 배치의 평균은 0, 분산은 1이 되도록 정규화
  • 정규화 이후, 배치 데이터들을 gamma, beta를 통해 새로운 값으로 바꾼다
  • gamma, beta는 층의 뉴런마다 하나씩 가진다
  • 스케일 조정-gamma & beta, 이동 평균-moving_mean, moving_variance

테스트 단계

  • 평균과 분산을 계산할 미니 배치가 없으므로 전체 훈련 데이터의 평균과 분산을 사용

🖥 케라스로 배치 정규화 구현

model = keras.models.Sequential([
	keras.layers.Flatten(input_shape=[28,28]),
    	keras.layers.BatchNormalization(),
    	kears.layers.Dense(300, activation='elu', 
    		       	   kernel_initializer='he_normal'),
    	keras.layers.BatchNormalization(),
        kears.layers.Dense(100, activation='elu', 
    		       	   kernel_initializer='he_normal'),
        keras.layers.BatchNormalization(),
        kears.layers.Dense(10, activation='softmax'
])

2. 전이학습 및 비지도 사전훈련

2-1. 전이학습

  • 비슷한 유형의 문제를 처리한 신경망의 하위층을 재사용하는 학습 방법
  • 훈련 속도 높이고 훈련 데이터 수도 줄일 수 있다

✔️ 케라스를 활용한 전이학습

  • 모델 A : 8개의 클래스를 분류하는 패션 MNIST에서 좋은 성능의 모델
  • TODO -> 샌들과 셔츠를 구분하는 이진 분류기 모델 B를 만들자
    1) 모델 A 로드
    2) 모델 A의 층을 재사용하여 새로운 모델 생성(출력층을 제외한 모든 층은 재사용)
    3) 모델 B를 훈련할 때 모델 A에 영향이 갈 수 있기 때문에 모델 A를 클론하여 가중치를 복사
    4) 훈련되지 않은 모델 B의 출력층은 랜덤하게 초기화 되어 있기 때문에 재사용된 모델 A의 층들은 동결하고 새로운 출력층은 학습할 시간을 준다
    5) 훈련
    6) 재사용된 층 동결 해제(이때, 학습률을 낮추는 것을 추천)후 훈련

🖥 keras를 활용한 전이학습

model_A = keras.models.laod_model('model_A.h5')
# 모델 B에 model_A의 layer들 재사용
new_model_B = keras.models.Sequential(model_A.layers[:-1])
# 모델 B에 출력층 생성
new_model_B.add(keras.layers.Dense(1, activation='sigmoid'))

# model_A의 가중치 복사
model_A_clone = keras.models.clone_model(model_A)
model_A_clone.set_weights(model_A.get_weights())

# 동결 후 compile
for layer in new_model_B.layers[:-1]:
	layer.trainable = False
new_model_B.compile(loss='binary_crossentropy',
		    optimizer='sgd',
            	    metrics=['accuracy'])
                    
# 학습
history = nes_model_B.fit(X_train_B, y_train_B, epochs=4, 
			  validation_data=(X_valid_B, y_valid_B))

for layer in new_model_B.layers[:-1]:
	layer.trainable = True
   
# 동결 해제 후 compile
optimizer = keras.optimizer.SGD(lr=1e-4) # 기본 학습률:1e-2
new_model_B.compile(loss='binary_crossentropy',
		    optimizer=optimizer,
          	    metrics=['accuracy'])

# 학습
history = new_model_B.fit(X_train_B, y_train_B, epochs=16, 
			  validation_data=(X_valid_B, y_valid_B))

2-2. 비지도 사전훈련

  • 레이블 된 데이터가 적을 때, 복잡한 문제를 다룰 때 사용
  • 일반적으로 한 번에 비지도 학습 모델 훈련 후 오토인코더 or GAN 사용

3. 최적화 방법

대규모 모델의 훈련 속도 높임

3-1. 모멘텀 최적화

  • 이전 그레디언트가 얼마였는지가 중요
  • 그래디언트를 가속도로 사용
    (이때, 모멘텀이 넘 커지는 것을 막기 위해 beta 하이퍼 파라미터 사용)
  • 일반적인 모멘텀 값은 0.9
optimizer = keras.optimizers.SGD(lr=0.001, momentum=0.9)

3-2. 네스테로프 가속 경사

  • 모멘텀 최적화의 변종으로 기본 모멘텀 최적화보다 훈련 속도가 빠름
  • 원래 위치보다 그 방향으로 조금 더 나아가서 측정한 그레디언트를 계산
optimizer = keras.optimizer.SGD(lr=0.001 momentum=0.9, nesterov=True)

3-3. AdaGrad

  • learning rate 값을 조절
  • 가장 가파른 차원을 따라 그레디언트 벡터의 스케일을 감소
  • 즉, 학습률을 감소(학습률이 너무 작으면 학습 시간 오래 걸림 & 학습률이 너무 크면 발산하는 문제 해결)
  • 심층 신경망에서 사용 X

3-4. Adam

  • 모멘텀 최적화 + RMSProp
  • (모멘텀) 지난 그레디언트 지수 감소 평균 & (RMSProp) 지난 그레디언트 제곱의 지수 감소된 평균
  • 학습률 하이퍼파라미터 튜닝할 필요 X
optimizer = keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999)

3-5. 학습률 스케줄링

  • 일정한 학습률이 아닌 훈련하는 동안 학습률을 감소시키는 전략
  • 대표적으로 성능 기반 스케줄링(ReduceLROnPlateau 콜백)
lr_scheduler = keras.callbacks.ReduceLROnPlateau(factor=0.5, patience=5)
  • 성능 기반 스케줄링은 valid_loss가 5번의 epochs동안 줄어들지 않으면 학습률에 0.5를 곱한다

4. 규제 기법

규제를 사용하면 과대적합을 피할 수 있다.

  • 조기 종료, 배치 정규화
  • 신경망에서 널리 사용되는 규제 기법들(l1&l2, dropout, ...)

4-1. l1 & l2 규제

l1 규제

  • 희소모델 만들기 위해 사용

l2 규제

  • 신경망의 연결 가중치를 제한

🖥 partial을 사용한 l2 규제

from functools import partial
RegularizedDense = partial(keras.layers.Dense,
			   activation='elu',
               		   kernel_initializer='he_normal',
                       	   kernel_regularizer=keras.regularizers.l2(0.01))

model = keras.models.Sequeuntial([
    keras.layers.Flatten(input_shape=[28,28]),
    RegularizedDense(300),
    RegularizedDense(100),
    RegularizedDense(10, activation='softmax', 
    		     kernel_initializer='glorot_uniform')
])
  • partial : 모든 은닉층에 동일한 매개변수 값을 반복하는 경우가 많을 때 코드 리팩터링 방법

4-2. 드롭아웃

  • 심층신경망에서 가장 인기 있는 규제 기법
  • 입력값의 작은 변화에 덜 민감해져서(이웃한 뉴런에 의존할 수 없도록) 더 안정적인 네트워크가 되기 위해 사용하는 규제 기법
  • 매 훈련 스텝에서 각 뉴런이 임시적으로 드롭아웃될 확률 p를 10% ~ 50% 사이로 지정
  • 훈련이 끝난 후에 뉴런에 더는 드롭아웃 적용X
  • 모델이 과대적합 되었을 때 드롭아웃 비율⬆️,
    모델이 과소적합 되었을 때 드롭아웃 비율⬇️
model = keras.models.Sequential([
    keras.layers.Flatten(input_shape=[28,28]),
    keras.layers.Dropout(0.2),
    keras.layers.Dense(300, activation='elu', 
    			kernel_initializer='he_normal'),
    keras.layers.Dropout(0.2),
    keras.layers.Dense(100, activation='elu', 
    			kernel_initializer='he_normal'),
    keras.layers.Dropout(rate=0.2),
    keras.layers.Dense(10, activation='softmax')
])

좋은 웹페이지 즐겨찾기