Mobile Network(Transfer Learning)

jaegoo1199·2021년 7월 31일
0

Deep Learning

목록 보기
9/12
post-thumbnail

Create the Dataset and Split it


케라스(Keras) 모듈을 이용하여 심층학습을 시도할 때, 디스크에 저장된 이미지 파일을 불러오는 것이 가장 간단하며 쉬운 방법이다. 이를 위해서는 image_data_set_from_directory() 함수를 이용하여 섞기 과정과 학습 예제, 입증 예제를 분할하여 예제를 불러올 수 있다.

from tensorflow.keras.preprocessing import image_dataset_from_directory

BATCH_SIZE = 32
IMG_SIZE = (160, 160)
directory = "location/"
train_dataset = image_dataset_from_directory(directory,
                                             shuffle=True,
                                             batch_size=BATCH_SIZE,
                                             image_size=IMG_SIZE,
                                             validation_split=0.2,
                                             subset='training',
                                             seed=42)

입증 예제를 위한다면 subsetvalidation으로 설정할 수 있다.

Preprocssing and Augnent Training Data


Prefetch

학습의 효율을 가장 높이기 위해선 가능한 많은 양의 데이터를 디스크에서 불러와 GPU에 전달을 하는 것이 중요하다. 하지만 이 상황에서 CPU에 부하가 커지고 실제로 원하는 만큼의 데이터 로딩이 어려워 지는 메모리 병목현상(memory bottleneck)이 발생하게 된다.

이를 해결하게 위해서 학습을 진행하면서 배치의 사이즈의 배수 혹은 그보다 많은 양의 데이터를 지속적으로 읽는 과정이 필요하다. 이러한 미리읽기(prefetch) 과정을 시도하여 병목현상을 줄일 수 있다. 위의 사진은 읽기(read)를 하면서 학습(train)을 하고 있는 파이프라이닝(pipelining)의 모습이다.

AUTOTUNE = tf.data.experimental.AUTOTUNE
train_dataset = train_dataset.prefetch(buffer_size=AUTOTUNE)

AUTOTUNE을 통해서 미리읽기를 하는 양의 데이터를 적절히 조절할 수 있다.

Data Augmentation

이미지 파일을 증강하여 수정하는 것은 컴퓨터 비전분야에서 흔히 있는 일로, 부족한 데이터의 양을 보완하고 학습할 예제들의 다양성을 증가시킬 수 있는 매우 일반적인 방법에 해당한다. 이미지 파일의 증강은 tf.keras.Sequential([])을 이용하여 증강 방식을 선택할 수 있다.

def data_augmenter():

    data_augmentation = tf.keras.Sequential([])
    data_augmentation.add(RandomFlip('horizontal'))
    data_augmentation.add(RandomRotation(0.2))

    return data_augmentation

위의 코드에서는 수평방향으로 뒤집고 회전을 시키는 증강 방법을 Sequential에 추가하였다.

MobileNetV2


모바일 신경망(MobileNetV2)은 이미지넷(ImageNet)에서 학습되고 휴대기기와 같은 저전력 기기에서 사용되도록 최적화된 신경망이다. 모바일 신경망의 특징은 다음과 같이 정리할 수 있다.

Depthwise Separable Convolution

  • Depthwise Convolution
    채널끼리의 합성곱 작업을 하게된다. 1번 채널은 이미지 파일의 1번 채널과 합성곱을 적용하게 된다. 이러한 방식은 계산 비용(computational cost)를 기존의 합성곱과 비교하였을 때, 현저하게 줄어드는 효과를 가져온다.
  • Pointwise Convolution
    점끼리의 합성곱 과정은 깊이끼리의 합성곱 과정에서 발생하는 채널의 수를 조절하는 역할을 한다. 깊이끼리의 합성곱 과정에서는 반드시 채널의 수가 필터의 수가 되기 때문에 기존에 계획한 채널의 형태로 맞추기 위해서 사용된다.

Thin Input Bottleneck layer

모바일 신경망(MobileNetV2)에서는 입력값의 차원이 작은 병목 구조를 가지게 된다. 입력값은 확장 과정에서 채널의 수가 증가하고 이는 계산과정을 풍부하게(richer computation) 하는 결과를 가져오게 된다. 이후 깊이끼리의 합성곱과 점끼리의 합성곱으로 다시 수축을 시켜서 한 층의 연산이 끝나게 된다.

Residual connection

위에서 설명한 병목 구조 외에도 지름길을 만들어서 잔여 블록을 형성하게 된다. 잔여블록의 경우는 잔여 신경망의 기능과 마찬가지로 학습의 속도와 예측의 성능을 높이기 위한 방향으로 진행이 되며, 비선형 활성함수는 적용하지 않는다.

Transfer Learning


전이 학습에서 미리 학습된 모델을 사용할 시에는 학습된 가중치를 그대로 사용하는 것이 가장 좋은 아이디어이다.

Loading Base Model

IMG_SHAPE = IMG_SIZE + (3,)
base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE,
                                               include_top=True,
                                               weights='imagenet')

위의 과정은 미리 훈련된 모델을 로드하는 과정이다. base_model.summary()를 통해서 기반 모델의 정보를 출력할 수 있다. 기반 모델인 모바일 신경망이 어떤식으로 결과물을 산출하는지 확인을 할 필요가 있다.

image_batch, label_batch = next(iter(train_dataset))
feature_batch = base_model(image_batch)

feature_batch의 차원은 (32, 1000)으로 배치의 크기와 모델이 사전에 학습한 집단의 수를 나타낸다. 하지만 전이학습을 통해서 구별하고자 하는 데이터의 라벨이 없을 경우가 다반사이기 때문에 일부 층을 수정하여 미세 조정(fine tuning)을 해야한다.

Layer Freezing

사전의 훈련된 모델을 이요하여 다시 미세하게 훈련을 시킬 필요가 있다. 이를 위해선 다음과 같은 과정이 필요하다.

  1. 분류층(classification layer)을 제거한다.
    • 기반 모델의 include_topFalse로 설정한다.
  2. 새로운 분류층을 추가한다.
    • 몇개의 신경세포가 필요한지 결정한다.
  3. 기존의 사전 훈련 모델은 동결(freezing) 후, 새롭게 추가된 층에 대해서 훈련을 시작한다.
    • base_model.trainable=False
    • base_model(x, training=False)를 통해 배치 정규화 과정에서 인지를 추적하는 것을 방지한다.
def alpaca_model(image_shape=IMG_SIZE, data_augmentation=data_augmenter()):
    input_shape = image_shape + (3,)

    base_model = tf.keras.applications.MobileNetV2(input_shape=input_shape,
                                                   include_top=False, # <== Important!!!!
                                                   weights='imagenet') # From imageNet
    
    # Freeze the base model by making it non trainable
    base_model.trainable = False

    # create the input layer (Same as the imageNetv2 input size)
    inputs = tf.keras.Input(shape=input_shape) 
    
    # apply data augmentation to the inputs
    x = data_augmentation(inputs)
    
    # data preprocessing using the same weights the model was trained on
    x = preprocess_input(x) 
    
    # set training to False to avoid keeping track of statistics in the batch norm layer
    x = base_model(x, training=False) 
    
    # Add the new Binary classification layers
    # use global avg pooling to summarize the info in each channel
    x = tfl.GlobalAveragePooling2D()(x) 
    #include dropout with probability of 0.2 to avoid overfitting
    x = tfl.Dropout(rate=0.2)(x)
        
    # create a prediction layer with one neuron (as a classifier only needs one)
    prediction_layer = tfl.Dense(units=1)
    
    outputs = prediction_layer(x) 
    model = tf.keras.Model(inputs, outputs)
    
    return model

위의 코드는 알파카인지 알파카가 아닌지 분류하는 신경망 모델을 새롭게 만든 것이다.

Fine Tuning

마지막 단계인 미세 튜닝을 적용할 차례이다. 정확도를 높이기 위해서 마지막 층에 최적화를 한번 더 진행을 하게된다. 특히 학습 비율(learning rate)을 기존의 훈련 방식보다 작게 학습을 할 경우 천천히 새로운 데이터에 대해서 더 정확하게 학습하게 된다.

위의 방식을 적용하기 위해선 마지막 층에대한 해동(unfreezing) 과정을 거쳐서 마지막 층에 대해서 매우 작은 학습 비율로 재학습을 시켜야 한다. 이에 대한 직관적인 이해는 이전 단계에서는 낮은 수준(low-level)에 대한 신경망을 학습이 되어 있고 이후 새로운 데이터로 학습을 하면서 높은 수준(high-level)에 대한 특징들을 학습하게된다. 전이 학습에서는 낮은 수준의 특징은 사전 훈련 모델과 비슷한(같은) 수준으로 유지한 상태(freezing)에서 새로운 데이터에 대한 적응 훈련을 한다고(unfreezing) 이해할 수 있다.

어느 지점 부터 마지막 층으로 볼 것인가는 다소 까다롭고 임의적인 문제이다. 대략적인 추측 정도면 충분하다. 가장 중요한 사실은 이후 층(later layers)들이 해결하려는 문제에 대한 세부적인 특징을 파악하는 부분이라는 점이다.

base_model = model2.layers[4]
base_model.trainable = True

# Fine-tune from this layer onwards
fine_tune_at = 120

# Freeze all the layers before the `fine_tune_at` layer
for layer in base_model.layers[:fine_tune_at]:
    layer.trainable = False
    
loss_function=tf.keras.losses.BinaryCrossentropy(from_logits=True)
optimizer = tf.keras.optimizers.Adam(lr=0.1*base_learning_rate)
metrics=['accuracy']

model2.compile(loss=loss_function,
              optimizer = optimizer,
              metrics=metrics)

Reference

profile
아직 거북이지만 곧 앞질러 갈겁니다.

0개의 댓글