[Computer Vision] 4(4). 전이학습 활용

5 minute read


전이학습 활용

정의


인간으로부터 영감 얻기

인간의 지식은 사람에서 사람으로, 세대에서 세대로 전달된다. 또한 개인으로서 사람은 하나의 작업에 대한 전문 지식을 다른 작업에 전이하는 능력도 있다.

이처럼 기존에 보유한 지식을 기반으로 복잡한 작업에 숙달하거나 비슷한 행동에 이미 가지고 있는 기술을 바꿔 적용하는 능력은 인간 지능에서 가장 중요한 부분이고, 머신러닝 연구원들은 이 능력을 복제하는 꿈을 꾸고 있다.


동기

사람과 다르게 대부분의 머신러닝 시스템은 실제로 지금까지 특정 단일 작업을 수행하기 위한 용도로 설계되었다. CNN은 특정 특징을 추출해 해석하도록 훈련됐기 때문에 특징 분포가 바뀌면 그 성능은 떨어지게 된다. 따라서 네트워크를 새로운 작업에 적용하려면 어느 정도의 변환 작업이 필요하다.

전이 학습은 다음과 같이 정의된다.

어떤 설정(예를 들어, 분포 P1)에서 학습된 내용이 다른 설정(예를 들어, 분포 P2)에서 일반화를 개선하기 위해 활용되는 상황

전이 학습은 새로운 작업을 적절하게 학습하기에 충분한 데이터가 확보되지 않았을 때 더욱 매력적이다. 대부분의 상황에서 데이터셋은 모델이 수렴할 만큼 충분하지 않기 때문에, 이러한 제약 사항은 잘 기록된 시각 작업에서 획득한 지식을 다른 경우에 재사용하기 위한 노력을 설명한다.

✋ 컴퓨터 비전 분야에서 지식을 전이할 모델을 찾는 사람들은 일반적으로 ‘ImageNet’으로 학습한 ‘Inception’ 또는 ‘ResNet-50’ 네트워크를 사용한다.


CNN 지식 전이

CNN을 위한 전이학습은 주로 다른 작업을 위한 새로운 모델을 인스턴스화하기 위해 풍부한 데이터셋에서 훈련된 성능 좋은 네트워크의 아키텍처 전체 혹은 일부와 가중치를 재사용하는 것으로 구성된다. 새로운 모델은 이 조건에 따라 인스턴스화한 다음 ‘미세조정’될 수 있다. 즉, 새로운 작업/도메인에 대해 활용할 수 있는 데이터에서 더 훈련될 수 있다.



활용 사례


어떤 모델을 재사용해야 할까? 어느 계층을 고정시키고 어느 계층을 미세조정해야 할까? 이 질문에 대한 답은 목표한 작업과 모델이 이미 훈련한 작업이 얼마나 비슷한지, 그리고 새로운 애플리케이션을 위한 훈련 샘플이 얼마나 풍부한 지에 따라 다르다.


1. 제한적 훈련 데이터로 유사한 작업 수행

말벌과 꿀벌을 구분하는 모델을 훈련시키고 싶다고 하자. 실제로 ImageNet에는 이 두 클래스에 대한 훈련 데이터들이 있지만, 이 데이터만으로 학습을 할 만큼 충분하지 않다. 이러한 경우에 전체 ImageNet 데이터셋에서 1000개의 카테고리로 분류하도록 훈련된 네트워크의 마지막 밀집계층을 제거하고 목표한 두 개의 클래스에 대해 예측을 출력하도록 설정된 계층으로 교체할 수 있다.

또한 이러한 경우 이 새로운 모델은 미리 훈련된 계층을 고정(매개변수의 업데이트를 허용하지 않음)시키고 상단에 위치한 밀집 계층만 훈련(목표한 분류 클래스의 데이터들로)시킴으로써 목표한 작업을 수행하도록 준비할 수 있다. 목표 훈련 데이터셋이 너무 작기 때문에 모델에서 특징 추출기의 구성 요소를 고정시키지 않으면 모델이 과적합될 수 있다. 이 매개변수를 고정시킴으로써 네트워크가 더 풍부한 데이터셋에서 개발한 표현력을 유지할 수 있게 된다.


2. 풍부한 훈련 데이터로 유사한 작업 수행

이런 경우 보통 특징 추출기의 최신 계층을 고정시켰던 것을 해제한다.

목표 데이터셋이 클수록 안전하게 미세 조정할 수 있는 계층이 많아진다. 이로써 네트워크는 새로운 작업과 관련성이 높은 특징을 추출하고 그 결과 새로운 작업을 수행하는 방법을 더 잘 학습할 수 있다.


3. 풍부한 훈련 데이터로 유사하지 않은 작업 수행

원래 훈련 작업과 목표 작업의 유사성이 매우 낮은 경우 미리 훈련된 모델을 사용해야 하는 필요성은 낮아진다. 모델을 사전에 훈련시키거나 사전 훈련된 가중치를 내려받는 일이 비용이 높을 수 있다.

다만, 다양한 실험을 통해 연구원들은 대부분의 경우 무작위로 선정된 가중치보다 사전 훈련된 가중치(비슷하지 않은 용도로 훈련됐더라도)를 사용해 네트워크를 초기화하는 것으 더 낫다는 사실을 보여줬다.


4. 제한적 훈련 데이터로 유사하지 않은 작업 수행

심층 모델을 적용하고 용도에 맞게 조정하는 것이 적절한지 재검토할 필요가 있다. 그러한 모델을 작은 데이터셋에서 훈련시키면 과적합이 일어나고 깊이가 깊은 사전 훈련된 추출기는 특정 작업과는 매우 무관한 특징을 반환하게 된다.

하지만 CNN의 첫번째 계층이 저차원 특징에 반응한다는 점을 감안하면 여전히 전이학습에서 혜택을 볼 수 있다. 사전 훈련된 모델의 최종 예측 계층만 제거하는 것이 아니라, 작업에 너무 특화된 최종 합성곱 블록의 일부도 제거할 수 있다. 그런 다음 남은 계층 위에 얕은 분류기를 추가해 새로운 모델을 미세 조정할 수 있다.



텐서플로와 케라스로 전이학습 구현


모델 수술

앞선 포스팅들에서 ‘고급 CNN 아키텍처’를 다루면서 간접적으로 텐서플로 허브와 케라스 애플리케이션을 통해 제공되는 사전 훈련된 표준 모델을 가져와 새로운 작업을 위한 특징 추출기로 쉽게 변환하는 방법에 대해 보았다.

그렇지만 예를 들어 전문가가 제공하는 더 특수한 용도의 최신 CNN이나 일부 이전 작업을 위해 이미 훈련된 맞춤형 모델같은 비표준 네트워크를 재활용하는 것도 일반적이다.


계층 제거

처음으로 할 일은 사전 훈련된 모델의 마지막 계층을 제거해 특징 추출기로 변환하는 것이다.

케라스에서는 이 작업을 pop() 메서드로 수행할 수 있다.

for i in range(num_layers_to_remove):
    model.layers.pop()

Sequential 모델의 경우 layers 프로퍼티를 통해 계층 리스트에 접근할 수 있다.

그런데 계층을 실제로 제거하지 않고 그 계층을 ‘사용하지 않는 것’만으로 런타임 시 연산은 진행되지 않는다. 따라서 계층을 제거하는 대신 이전 모델에서 유지하고자 하는 마지막 계층/연산을 특정하면 된다.

for layer in model.layers:
    if layer.name == name_of_last_layer_to_keep:
        bottleneck_feats = layer.output
        break

케라스는 위 과정을 단순화하는 메서드를 제공한다. 유지할 최종 계층의 이름을 알면(model.summary()로 확인) 다음 코드 두 줄로 특징 추출기 모델을 구성할 수 있다.

bottleneck_feats = model.get_layer(last_layer_name).output
feature_extractor = Model(inputs=model.input, outputs=bottleneck_feats)

이 특징 추출 모델은 원본 모델과 이 가중치를 공유해서 사용할 준비가 됐다.


계층 이식

특징 추출기 상단에 새로운 예측 계층을 추가하는 일은 모델 상단에 새로운 계층을 추가하기만 하면 된다. 케라스 API로 다음과 같이 추가할 수 있다.

dense1 = Dense(num_classes, activation='softmax')(feature_extractor.output)
new_model = Model(model.input, dense1)

참고로, 이전 포스팅에서 다룬 텐서플로 허브에서 가져온 모델을 사용하여 계층 이식을 하는 방법도 첨부한다.

import tensorflow_hub as hub
from keras.models import Sequential
from keras.layers import Dense

num_classes = 1000

url = "https://tfhub.dev/google/tf2-preview/inception_v3/feature_vector/2"

hub_feature_extractor = hub.KerasLayer(     # Layer로서의 TF-Hub 모델
url,                      # TF-Hub 모델 URL
trainable=False,         # 모델 계층들을 훈련 가능하게 할지 여부를 설정하는 플래그
input_shape=(299,299,3),  # 예산 입력 형상 (tfhub.dev에서 확인)
output_shape=(2048,),     # 출력 형상(입력 형상과 동일, 모델 페이지에서 확인)
dtype=tf.float32)         # 예상 dtype

inception_model = Sequential([hub_feature_extractor, 
                              Dense(num_classes, activation='softmax')], 
                              name="inception_tf_hub")



선택적 훈련

전이학습을 사용하면 먼저 사전 훈련된 계층을 복원하고 어느 계층을 고정할 지 정의해야 하기 때문에 훈련 단계가 다소 복잡하다. 다행히도 이러한 작업을 단순화하기 위한 몇가지 도구가 있다.


사전 훈련된 매개변수 복원하기

텐서플로에는 에스티메이터를 웜스타트(warm-start, 사전에 훈련된 가중치를 사용해 일부 계층을 초기화)하는 유틸리티 함수가 있다.

다음 코드를 사용하면 텐서플로에서 새로운 에스티메이터를 위해 동일한 이름을 공유하는 계층의 경우 사전 훈련된 에스티메이터의 저장된 매개변수를 사용할 수 있다.

def model_function():
    # ...새로운 모델 정의, 사전 훈련된 모델을 특징 추출기로 재사용
    
    ckpt_path = '/path/to/pretrained/estimator/model.ckpt'
    ws = tf.estimator.WarmStartSettings(ckpt_path)
    estimator = tf.estimator.Estimator(model_fn, warm_start_from=ws)

케라스를 사용하면 새로운 작업에 맞춰 변환하기 전에 사전 훈련된 모델을 복원할 수 있다.

# 사전 훈련된 모델이 'model.save()'를 사용해 저장됐다고 가정
model = tf.keras.load_model('/path/to/pretrained/model.h5')
# 그런 다음 새로운 모델을 얻기 위해 계층을 빼거나 추가함

일부 계층을 제거하기 위해 전체 모델을 복원하는 것이 최적은 아니지만, 이 방법이 가장 간결하다.


계층 고정하기

텐서플로에서 계층을 고정하기 위해 가장 다양하게 사용되는 기법은 최적화기에 전달되는 매개변수 리스트에서 tf.Variable 특성을 제거하는 것이다.

# 예를 들어, 이름에 'conv'가 포함된 모델 계층을 고정하고자 함

vars_to_train = model.trainable_variables
vars_to_train = [v for v in vars_tp_train if "conv" in v.name]

# 최적화기를 남은 모델 변수에 적용함
optimizer.apply_gradients(zip(gradient, vars_to_train))

케라스의 계층에는 trainable 프로퍼티가 있고, 그 계층을 고정하기 위해 이 속성을 False로 지정하면 된다.

for layer in feature_Extractor_model.layers:
    layer.trainable = False # 전체 추출기를 고정

👍 자세한 전이학습 예제는 [Computer Vision] 4(5). 전이학습 예제에서 확인하세요!

Leave a comment