Machine Learning/[Kaggle Course] ML (+ 딥러닝, 컴퓨터비전)

Convolutional Classifier

WakaraNai 2021. 3. 29. 22:39
728x90
반응형

Introduction of Computer Vision

  1. Keras로 만든 image classifier에 현대 딥러닝 네트워크를 사용합니다
  2. 자신만의 custom convnet을 설계해봅니다.
  3. Visual feature extraction 속 아이디어를 배워봅니다.
  4. model의 속도를 올리기 위해 transfer learning을 배워봅니다.
  5. data augmentation을 적용하여 dataset을 확장시켜 봅니다.

이 수업의 목표는 신경망이 자연 세계의 이미지를 어떻게 이해하는지 그 방법을 배우는 것입니다. 이는 사람이 시각적으로 처리하는 체계뱡식과 유사합니다.

 

Convolutional Neural Networks (CNN or Convnet)

저마다 다른 구조의 convnet으로 된 레이어들을 반환하는 수학적 연산.

컴퓨터 비전, 즉 Image Classification에 적용하기 좋은 신경망.

 

Convolutional Classifier

convnet은 이미지 분류를 위해 convoutional base와 dense head, 두 과정으로 구성됩니다.

convolutional base이미지로부터 특징(feature)(선, 색깔, 질감, 모양, 패턴 등의 조합)을 추출하기 위해 사용됩니다. 주로 convolution 연산에 사용되는 레이어로 구성되지만 다른 종류의 레이어도 포함하기도 합니다.

dense head는 (특징에 따라) 이미지의 집단(class)를 결정하기 위해 사용됩니다. 주로 dense layer로 구성되지만 dropout같은 다른 레이어를 포함하기도 합니다.

 

 

 

Training the Classifier -> Transfer Learning

요즘은 convnets을 사전에 훈련된 모델을 기반으로 재사용합니다.

즉, 이미 훈련된 base에 훈련되지 않은 head를 부착합니다.

이미 base 단계를 마친 신경망의 일부를 재사용하고. 새로운 레이어 몇 개를 붙여서 특징을 추출하여 분류합니다.

 

head는 종종 적은 수의 dense layers로 구성되어 있기 때문에 매우 정확한 classifiers는 상대적으로 적은 data에서 생성될 수 있습니다.

이미 훈련된 모델을 재사용하는 것은 "transfer learning" 기법입니다.

이는 매우 효과적이며 요즘에는 모든 image classifier가 이 방법을 사용합니다.

 

Example - Train a Convnet Classifier

자동차와 트럭을 구분해주는 image classifier를 만들어봅시다.

dataset에는 약 10000 장의 다양한 차량 사진이 들어있습니다.

 

1. Load data

몇 가지 라이브러리를 불러와서 train set과 valid set을 준비해봅시다.

데이터를 준비하는 과정을 data pipeline이라고 합니다.

import os, warnings
import matplotlib.pyplot as plt
from matplotlib import gridspec

import numpy as np
import tensorflow as tf
from tensorflow.keras.preprocessing import image_dataset_from_directory

# Reproducability
def set_seed(seed=31415):
    np.random.seed(seed)
    tf.random.set_seed(seed)
    os.environ['PYTHONHASHSEED'] = str(seed)
    os.environ['TF_DETERMINISTIC_OPS'] = '1'
set_seed(31415)

# Set Matplotlib defaults
plt.rc('figure', autolayout=True)
plt.rc('axes', labelweight='bold', labelsize='large',
       titleweight='bold', titlesize=18, titlepad=10)
plt.rc('image', cmap='magma')
warnings.filterwarnings("ignore") # to clean up output cells


# Load training and validation sets
ds_train_ = image_dataset_from_directory(
    '../input/car-or-truck/train',
    labels='inferred',
    label_mode='binary',
    image_size=[128, 128],
    interpolation='nearest',
    batch_size=64,
    shuffle=True,
)
ds_valid_ = image_dataset_from_directory(
    '../input/car-or-truck/valid',
    labels='inferred',
    label_mode='binary',
    image_size=[128, 128],
    interpolation='nearest',
    batch_size=64,
    shuffle=False,
)

# Data Pipeline
def convert_to_float(image, label):
    image = tf.image.convert_image_dtype(image, dtype=tf.float32)
    return image, label

AUTOTUNE = tf.data.experimental.AUTOTUNE
ds_train = (
    ds_train_
    .map(convert_to_float)
    .cache()
    .prefetch(buffer_size=AUTOTUNE)
)
ds_valid = (
    ds_valid_
    .map(convert_to_float)
    .cache()
    .prefetch(buffer_size=AUTOTUNE)
)

Found 5117 files belonging to 2 classes.

Found 5051 files belonging to 2 classes.

 

 

 

2. Define Pretrained Base

예비 훈련에 가장 많이 쓰이는 dataset은 ImageNet입니다. 이는 다양한 실세계의 사진을 갖고 있습니다.

Keras는 ImageNet을 기반으로 이미 훈련된 다양한 모델을 가지고 있습니다.

그 모델은 applications module에 있고요.

 

이번에 사용할 이미 훈련된 모델의 이름은 'VGG16'입니다.

pretrained_base = tf.keras.models.load_model(
    '../input/cv-course-models/cv-course-models/vgg16-pretrained-base',
)
pretrained_base.trainable = False

 

 

 

3. Attach the Classifer Head

예로 hidden unit으로 구성된 레이어(첫번째 dense layer) 다음에 다른 레이어를 한 개 더 사용하여

Truck이란 집단 1의 확률점수로 결과를 변환합니다.

Flatten 레이어는 2차원 형태의 base의 출력 결과를 head에 필요한 1차원 형식의 입력값으로 변환합니다.

2차원 출력값이 1차원 형태로 바꿔줘야 하기에 평평해진다는 표현을 써보았죠.

from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    pretrained_base,
    layers.Flatten(),
    layers.Dense(6, activation='relu'),
    layers.Dense(1, activation='sigmoid'),
])

 

 

 

4. Train the model

현재 집단이 2개 뿐인 문제를 다루기 때문에 'cross-entropy'와 'accuracy'를 binary 버전으로 사용해야 합니다.

adam optimizer를 사용하여 해봅시다.

model.compile(
    optimizer='adam',
    loss='binary_crossentropy',
    metrics=['binary_accuracy'],
)

history = model.fit(
    ds_train,
    validation_data=ds_valid,
    epochs=30,
    verbose=0,
)

 

신경망을 훈련시킬 때  loss(손실)과 그래프를 평가해보는 것이 좋습니다.

history 객체는 이러한 정보를 history.history라는 딕셔너리에 보관합니다.

Pands로 이 딕셔너리를 dataframe으로 변환하여 그래프(plot)을 그려봅시다.

import pandas as pd

history_frame = pd.DataFrame(history.history)
history_frame.loc[:, ['loss', 'val_loss']].plot()
history_frame.loc[:, ['binary_accuracy', 'val_binary_accuracy']].plot();

loss도 0에 수렴하는 것을 보아 잘 감소하고 있고 정확도는 85%로 준수한 편이네요.

 

 

 


Exercise

# Setup feedback system
from learntools.core import binder
binder.bind(globals())
from learntools.computer_vision.ex1 import *

# Imports
import os, warnings
import matplotlib.pyplot as plt
from matplotlib import gridspec

import numpy as np
import tensorflow as tf
from tensorflow.keras.preprocessing import image_dataset_from_directory

# Reproducability
def set_seed(seed=31415):
    np.random.seed(seed)
    tf.random.set_seed(seed)
    os.environ['PYTHONHASHSEED'] = str(seed)
    os.environ['TF_DETERMINISTIC_OPS'] = '1'
set_seed()

# Set Matplotlib defaults
plt.rc('figure', autolayout=True)
plt.rc('axes', labelweight='bold', labelsize='large',
       titleweight='bold', titlesize=18, titlepad=10)
plt.rc('image', cmap='magma')
warnings.filterwarnings("ignore") # to clean up output cells


# Load training and validation sets
ds_train_ = image_dataset_from_directory(
    '../input/car-or-truck/train',
    labels='inferred',
    label_mode='binary',
    image_size=[128, 128],
    interpolation='nearest',
    batch_size=64,
    shuffle=True,
)
ds_valid_ = image_dataset_from_directory(
    '../input/car-or-truck/valid',
    labels='inferred',
    label_mode='binary',
    image_size=[128, 128],
    interpolation='nearest',
    batch_size=64,
    shuffle=False,
)

# Data Pipeline
def convert_to_float(image, label):
    image = tf.image.convert_image_dtype(image, dtype=tf.float32)
    return image, label

AUTOTUNE = tf.data.experimental.AUTOTUNE
ds_train = (
    ds_train_
    .map(convert_to_float)
    .cache()
    .prefetch(buffer_size=AUTOTUNE)
)
ds_valid = (
    ds_valid_
    .map(convert_to_float)
    .cache()
    .prefetch(buffer_size=AUTOTUNE)
)

 

 

ImageNet dataset에 대해 이미 훈련된 InceptionV1 모델을 사용해보려 합니다.

import tensorflow_hub as hub

pretrained_base = tf.keras.models.load_model(
    '../input/cv-course-models/cv-course-models/inceptionv1'
)

 

1. Define Pretrained Base for feature extraction

transfer learning을 할 때, 전체 base를 재훈련하는 것은 그닥 좋은 생각이 아닙니다.

그래서 이미 훈련된 base는 trainable을 false로 설정합니다. (pretrained_base.trainable = False)

그 이유는 head 속 무작위 값들로 된 가중치들이 처음에 아주 큰 기울기로 초기화하게 되기 때문입니다.

그러면 그 기울기로 인해 base 레이어들로 다시 전파되어 이미 훈련된 결과를 망치게 됩니다.

fine tuning 기법을 사용하면, 새로운 데이터에 대해 훈련을 진행할 수 있지만 이는 매우 조심해야 합니다.

 

2. Attach Head

dense layers의 head는 분류하는 기능이 있습니다. 

from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    pretrained_base,
    layers.Flatten(),
    layers.Dense(6, activation='relu'),
    layers.Dense(1, activation='sigmoid'),
])

 

3. Train

Keras에 있는 모델을 훈련하기 전에, 경사 하강법에 쓸 optimizer와 손실을 최소화할 loss function 그리고 performance metrics를 정해야 합니다.

최적화 알고리즘으로 'Adam'을 사용해봅시다.

loss function과 metrics는 다음과 같은 문제에 봉착할 수 있습니다.

binary classification problem이죠. 그래서 Car는 0으로 Truck은 1로 코딩하세요.

그리고 loss 와 metrics도 binary classification에 적합한 것으로 고르세요.

# YOUR CODE HERE: what loss function should you use for a binary
# classification problem? (Your answer for each should be a string.)
optimizer = tf.keras.optimizers.Adam(epsilon=0.01)
model.compile(
    optimizer=optimizer,
    loss = 'binary_crossentropy',
    metrics=['binary_accuracy'],
)

 

 

 

history = model.fit(
    ds_train,
    validation_data=ds_valid,
    epochs=30,
)

 

import pandas as pd
history_frame = pd.DataFrame(history.history)
history_frame.loc[:, ['loss', 'val_loss']].plot()
history_frame.loc[:, ['binary_accuracy', 'val_binary_accuracy']].plot();

 

4. Examine Loss and Accuracy

위의 InceptionV2의 learning curves와 VGG16의 learning curves의 차이점을 파악했나요?

어느 것이 더 나은가요?

 

training loss와 validation loss가 매우 가깝기 때문에 모델이 training data에서만 잘 작동하는 것이 아니라 두 집단의 속성을 잘 학습하고 있다고 말할 수 있습니다.

이 모델은 loss에서는 VGG16모델 보다 급격하게 loss가 수렴하고 있으므로, 때때로 underfitting이 일어날 수도 있습니다. 

장점으로 추가적으로 필요한 공간을 절약할 수 있다는 점이 있습니다.

 

728x90
반응형