본문 바로가기
코딩/데이터 분석 이론 & 응용

[14] Deep Learning - Transfer Learning & Pre-training

반응형

[14] Deep Learning - Transfer Learning & Pre-training

 

 

 

Transfer Learning

 

큰 규모의 Network를 학습할 때 , 모든 weight를 처음부터 새로 훈련하려 하면 속도도 느리고 , 시간도 오래 걸릴 것이다. 비슷한 문제를 해결한 Network가 이미 존재한다면 그 Network의 layer를 재사용해서 시간을 단축시킬 수 있다. 이러한 방법이 바로 Transfer Learning , 전이 학습이다. 전이 학습은 훈련속도를 보다 빠르게 해 줄 뿐만 아니라 훈련에 필요한 데이터 수도 줄여준다.

 

 

 

 

전이 학습

 

 

 

당연하게도 재사용하는 Network의 문제가 새로 해결해야하는 문제와 비슷할수록 더 많은 layer를 재사용할 수 있다. 또한 재사용할 layer의 개수 역시 생각해보아야 한다. 

 

 

위의 그림에서 나와있듯이 , 재사용하는 층의 weight를 변하지 않도록 얼려서 사용할 수 있다. 일반적으로 재사용하는 layer의 모든 weight를 얼려서 변하지 않도록 한 후에 모델을 훈련한다. 이후 몇 개의 층을 해동시켜 weight가 어떻게 변하는지 , 성능이 이전보다 좋아지는지를 확인한다. 이러한 방식을 통해 최적의 모델을 찾을 수 있다. 만약 결과가 좋지 못하다면 , 재사용하는 layer가 의미가 있는지 , 재사용 layer의 개수가 적은 지 , 많은지에 대해서 생각해볼 수 있다.

 

 

keras를 통해 전이 학습을 구현하는 방법은 다음과 같다.

 

 

 

model_A = keras.models.load_model("original_model.h5")
model_B_on_A = keras.models.Sequential(model_A.layers[:-1])
model_B_on_A.add(keras.layers.Dense(1, activation="sigmoid"))

 

 

 

위의 코드는 첫번쨰 줄 , load_model을 통해 저장된 model을 불러왔다. 이후 model_B_on_A에 불러온 model_A의 layer를 재사용했다. 위 코드의 경우 재사용이라는 표현도 맞지만 , 공유한다고도 볼 수 있다. 만약 공유하지 않고 재사용하려면 clone_model() 메소드를 사용해야 하며 , 이 경우 가중치는 복사되지 않기 때문에 가중치를 따로 복사해야 한다. clone_model() 메소드를 사용하는 방법은 아래와 같다.

 

 

 

 

model_clone = keras.models.clone_model(model_original)
model_clone.set_weights(model_original.get_weights())

 

 

 

재사용한 층을 더해 훈련하기 앞서 얼릴 층을 정해야 한다. 아래의 코드를 보면 .trainable을 False로 두어 훈련이 불가능하게 , 즉 weight를 얼리는 것을 볼 수 있다. 층을 얼리거나 녹인 후에는 모델을 컴파일해야 한다.

 

 

 

for layer in model_B_on_A.layers[:-1]:
	layer.trainable = False
    
model_B_on_A.compile(loss = "binary_crossentropy" , optimizer="sgd",
	metrics=["accuracy"])

 

 

 

 

만약 위의 코드처럼 모델을 훈련했다면 , 훈련이 끝난 이후에는 얼려놨던 층을 녹여서 다시 컴파일 해야한다. 즉 재사용된 layer의 weight를 다시 세밀하게 조정하는 것이다. 이 과정에서 본래의 weight를 심하게 훼손하지 않으려면 학습률 , lr을 낮추어서 진행하는 것이 좋다.

 

 

 

history = model_B_on_A.fit(X_train_B , y_train_B , epochs=4,
	validation_data=(X_valid_B , y_valid_B))
    
for layer in model_B_on_A.layers[:-1]:
	layer.trainable = True 
    #얼린 층을 다시 녹여서 사용함
    
optimizer = keras.optimizers.SGD(lr=1e-4)
#weight가 훼손이 덜되도록 lr을 낮춤 1e-2 -> 1e-4

model_B_on_A.compile(loss="binary_crossentropy", optimizer=optimizer,
	metrics=["accuracy"])
    
history = model_B_on_A.fit(X_train_B, y_train_B, epochs=16,
	validation_data=(X_valid_B , y_valid_B))

 

 

 

전이 학습은 작은 fully connected Network에서는 잘 동작하지 않는다. 작은 network에서는 패턴 수를 적게 학습하고 , fully connected network는 특정 패턴을 학습하기 때문이다. 전이 학습은 일반적인 특성을 감지하는 경향이 있기 때문에 알맞지 않다.

 

 

이를 고려하지 않고 재사용한 층에 결과를 맞추려고 하는 것은 좋지 않다. 이처럼 억지로 결과를 좋게 보이게 만들거나 데이터를 선별해 좋은 결과가 나오도록 조작하는 등 , 결과에 대한 유혹은 언제나 존재한다. 이런 부분을 걷어낼 수 있어야 한다. 논문을 읽을 떄도 결과가 너무 지나치게 좋아 보인다면 , 의심해 보고 사용해볼 필요가 있다.

 

 

 

 

Pre-training

 

사용할만한 문제 해결 모델이 없어 전이 학습을 사용할 수 없는 경우 , 사용할 수 있는 방법으로 Pre-training , 사전 훈련 방법이 있다. 전이 학습도 사용하지 못하고 , label된 데이터의 수가 적은 경우를 살펴보자. 이 경우 사용할 수 있는 사전 훈련 방법으로는 비지도 사전훈련이 있다. 비지도 학습 모델을 통해서 모델을 학습하고 , 이후 지도 학습을 통해 세밀하게 network를 튜닝한다는 아이디어이다.

 

 

비지도 사전 학습과 관련된 방법으로는 오토인코더 , Generative Adversarial Network , GAN이 있다. GAN은 생성적 적대 신경망이라고 한다. 오토인코더나 GAN으로 비지도 학습 모델을 훈련하고 , 이후 지도 기법을 통해 network를 세밀하게 튜닝한다. 과거에는 비지도 학습 모델 부분을 한층씩 훈련했지만 , 요즘에는 전체 모델을 바로 훈련할 수 있다.

 

 

이에 더불어 보조 작업을 위해 network를 사전 학습하고 이를 활용하는 방법이 있다. 즉 모델을 본래 해결해야 하는 문제보다 가벼운 문제를 해결하는 모델로 학습하고 , 이를 통해 얻은 특성을 이후 어려운 문제를 해결하는 데에 사용하는 것이다.

 

 

자기 지도 학습은 비지도 학습처럼 스스로 label을 생성하고 , 생성된 label을 이용해 지도 학습으로 모델을 학습하는 방법이다. 위의 방법들과 달리 사람이 label을 부여할 필요가 없으므로 비지도 학습의 일부로 분류된다.

 

 

 

 

 

 

 

 

ref. "Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow, 2nd Edition"

 

 

반응형