안녕하세요.

이번 장에서는 지난시간에 배운 내용들을 토대로 코드를 작성해보도록 하겠습니다.

첫 번째에는 아예 새로운 CNN 모델을 구축(by Functional API)하여 학습시키는 방식을 구현하고, 두 번째에는 pre-trained model을 다운받아 transfer learning과 fine-tuning을 적용시킨 방식을 구현해보도록 하겠습니다. 

 

 

 

1. New model 구축 버전

import os
from tensorflow import keras
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras import layers
from tensorflow import keras
import matplotlib.pyplot as plt
import math

base_dir 경

 

base_dir = './datasets/COVID_19/'
train_dir = os.path.join(base_dir, 'train')
validation_dir = os.path.join(base_dir, 'validation')


train_datagen = ImageDataGenerator(
    featurewise_center=True,
    featurewise_std_normalization=True,
    rescale=1./255,
    rotation_range=20,
    width_shift_range=0.2,
    height_shift_range=0.2,
    horizontal_flip=True,
    validation_split=0.2)
 
 validation_datagen = ImageDataGenerator(rescale=1./255)
 
 
 train_generator = train_datagen.flow_from_directory(
        # 타깃 디렉터리
        train_dir,
        # 모든 이미지를 150 × 150 크기로 바꿉니다
        target_size=(150, 150),
        batch_size=32,
        # categorical_crossentropy 손실을 사용
        class_mode='categorical') #COVID_19는 3개의 클래스로 구성됨
        
 validation_generator = validation_datagen.flow_from_directory(
        validation_dir,
        target_size=(150, 150),
        batch_size=32,
        class_mode='categorical')
 
input_shape = (150,150,3)
img_input = layers.Input(shape=input_shape)
output1 = layers.Conv2D(kernel_size=(3,3), filters=32, activation='relu')(img_input)
output2 = layers.MaxPooling2D((2,2))(output1)
output3 = layers.Conv2D(kernel_size=(3,3), filters=64, activation='relu')(output2)
output4 = layers.MaxPooling2D((2,2))(output3)
output5 = layers.Conv2D(kernel_size=(3,3), filters=128, activation='relu')(output4)
output6 = layers.MaxPooling2D((2,2))(output5)
output7 = layers.Conv2D(kernel_size=(3,3), filters=128, activation='relu')(output4)
output8 = layers.MaxPooling2D((2,2))(output7)
output9 = layers.Flatten()(output8)
output10 = layers.Dropout(0.5)(output9)
output11 = layers.Dense(512, activation='relu')(output10)
predictions = layers.Dense(2, activation='softmax')(output11)

model = keras.Model(inputs=img_input, outputs=predictions)

model.summary()
opt = SGD(lr=INIT_LR, momentum=0.9)
loss = CategoricalCrossentropy(label_smoothing=0.1)
model.compile(loss=loss, optimizer=opt, metrics=["accuracy"])
train_step = math.ceil(train_generator.n/32)
valid_step = math.ceil(valid_generator.n/32)

history = model.fit_generator(
      train_generator,
      steps_per_epoch=train_step,
      epochs=30,
      validation_data=validation_generator,
      validation_steps=valid_step)
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(len(acc))

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()

plt.figure()

plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()

plt.show()
model.save('CNN_epoch_20.h5')

test_dir = os.path.join(base_dir, 'test')
test_datagen = ImageDataGenerator(rescale=1./255)
test_generator = test_datagen.flow_from_directory(
        test_dir,
        target_size=(150, 150),
        batch_size=32,
        class_mode='binary')

test_step = math.ceil(test_generator.n/32)

test_loss, test_acc = model.evaluate_generator(test_generator, steps=test_step, workers=4)
print(f'test loss : {test_loss:.4f} / test acc : {test_acc*100:.2f} %')

 

 

 

 

 

2. Pre-trained model with transfer learning an fine tuning 구축 버전

import os
from tensorflow import keras
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras import layers
from tensorflow import keras
from tensorflow.keras.applications import VGG16
import matplotlib.pyplot as plt
import math

base_dir 경

 

base_dir = './datasets/COVID_19/'
train_dir = os.path.join(base_dir, 'train')
validation_dir = os.path.join(base_dir, 'validation')


train_datagen = ImageDataGenerator(
    featurewise_center=True,
    featurewise_std_normalization=True,
    rescale=1./255,
    rotation_range=20,
    width_shift_range=0.2,
    height_shift_range=0.2,
    horizontal_flip=True,
    validation_split=0.2)
 
 validation_datagen = ImageDataGenerator(rescale=1./255)
 
 
 train_generator = train_datagen.flow_from_directory(
        # 타깃 디렉터리
        train_dir,
        # 모든 이미지를 150 × 150 크기로 바꿉니다
        target_size=(150, 150),
        batch_size=32,
        # categorical_crossentropy 손실을 사용
        class_mode='categorical') #COVID_19는 3개의 클래스로 구성됨
        
 validation_generator = validation_datagen.flow_from_directory(
        validation_dir,
        target_size=(150, 150),
        batch_size=32,
        class_mode='categorical')
 
vgg_base = VGG16(weights='imagenet',
                  include_top=False,
                  input_shape=(150, 150, 3))
vgg_base.summary()

model = models.Sequential()
model.add(vgg_base)
model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dense(3, activation='softmax'))
for layer in vgg_base.layers:
	layer.trainable = False
    
for layer in vgg_base.layers[15:]:
	layer.trainable = True
opt = SGD(lr=INIT_LR, momentum=0.9)
loss = CategoricalCrossentropy(label_smoothing=0.1)
model.compile(loss=loss, optimizer=opt, metrics=["accuracy"])
train_step = math.ceil(train_generator.n/32)
valid_step = math.ceil(valid_generator.n/32)

history = model.fit_generator(
      train_generator,
      steps_per_epoch=train_step,
      epochs=30,
      validation_data=validation_generator,
      validation_steps=valid_step)
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(len(acc))

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()

plt.figure()

plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()

plt.show()
model.save('CNN_epoch_20.h5')

test_dir = os.path.join(base_dir, 'test')
test_datagen = ImageDataGenerator(rescale=1./255)
test_generator = test_datagen.flow_from_directory(
        test_dir,
        target_size=(150, 150),
        batch_size=32,
        class_mode='binary')

test_step = math.ceil(test_generator.n/32)

test_loss, test_acc = model.evaluate_generator(test_generator, steps=test_step, workers=4)
print(f'test loss : {test_loss:.4f} / test acc : {test_acc*100:.2f} %')

 

안녕하세요. 

이번 글에서는 transfer learning과 fine-tuning을 하는 tensorflow code를 살펴보도록 하겠습니다.

 

 

 

1. Transfer Learning

아래 코드를 실행시키고 자세히 보면 prediction part(→Flatten, Dense layer 부분이 빠져있는걸 확인할 수 있습니다)

from tensorflow.keras.applications import VGG16

vgg_base = VGG16(weights='imagenet',
                  include_top=False,
                  input_shape=(150, 150, 3))
vgg_base.summary()

 

Prediction layers 분은 굳이 Functional API로 구현할 필요는 없기 때문에 sqeuntial로 prediction layer 부분을 추가해 줍니다.

from tensorflow.keras import models
from tensorflow.keras import layers

model = models.Sequential()
model.add(vgg_base)
model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
model.summary()

 

위와 같이 model을 구성했다면 이전에 배운대로 아래 코드를 수행시켜 학습을 실행시킵니다.

model.compile(optimizer=optimizers.RMSprop(lr=2e-5),
              loss='binary_crossentropy',
              metrics=['acc'])

history = model.fit(train_features, train_labels,
                    epochs=30,
                    batch_size=20,
                    validation_data=(validation_features, validation_labels))

 

 

 

2. Fine tuning

위와 같이 transfer learning을 적용시킨 후 특정 layer들만 학습시키려면 우선 아래와 같이 Convolution base 부분을 아래 코드와 같이 freezing 시킵니다.

for layer in vgg_base.layers:
	layer.trainable = False

 

 

보통 fine tuning을 할 때, 끝단에 위치한 bottom conv layer (=deeper layer) 부분만 미세하게 학습시켜주는 것이 일반적입니다. 왜냐하면, 어떠한 이미지분류 문제이든 해당 객체의 edge(←top layer의 conv filter가 뽑는 feature)는 거의 비슷할 테니까요. 중간 layer에 있는 conv filter가 보통 texture feature를 뽑아내는데, 만약 ImageNet에서 학습한 이미지의 texture와 내가 분류하려는 새로운 이미지들의 texture가 많이 다르다는 판단을 하게 된다면 이 부분도 미세하게 학습시켜주어야 합니다. 이러한 방법은 아래와 같은 코드로 진행이 됩니다.

for layer in vgg_base.layers[15:]:
	layer.trainable = True

 

 

[정리]

지금까지 배운 pre-trained model을 다운받아 transfer learning 및 fine-tuning을 적용시키는 코드를 작성해보도록 하겠습니다.

from tensorflow.keras import models
from tensorflow.keras import layers
from tensorflow.keras.applications import VGG16
vgg_base = VGG16(weights='imagenet',
                  include_top=False,
                  input_shape=(150, 150, 3))
vgg_base.summary()
for layer in vgg_base.layers:
	layer.trainable = False
for layer in vgg_base.layers[15:]:
	layer.trainable = True
model = models.Sequential()
model.add(vgg_base)
model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dense(2, activation='softmax'))
model.compile(optimizer=optimizers.RMSprop(lr=2e-5),
              loss='categorical_crossentropy',
              metrics=['acc'])

history = model.fit(train_features, train_labels,
                    epochs=30,
                    batch_size=20,
                    validation_data=(validation_features, validation_labels))

 

 

3. Model 저장 및 불러오기

앞선 작업을 통해 학습시킨 CNN 모델을 따로 저장할 수 도 있고, 나중에 데이터셋이 더 마련되면 해당 CNN 모델을 불러와 다시 re-training 시킬 수 있습니다.

 

tensorflow에서 CNN 모델을 저장시키거나 불러올 때 사용되는 CNN 모델 파일 format은 TensorFlow SavedModel 형식 or Keras H5 형식 or checkpoint 형식으로 크게 세 가지가 있습니다.

 

 

3-1. h5 파일 형태로 저장 또는 불러오기

tensorflow에서는 학습시킨 모델을 h5 형태의 파일로 저장시킬 수 있습니다. 본래 h5 형태의 파일은 keras에서 지원하던 파일형식인데 keras가 tensorflow backend를 사용할 때 tf.keras 로 h5 형태의 파일을 저장 및 불러오는 것을 가능하게 했습니다.

# Calling `save('my_model.h5')` creates a h5 file `my_model.h5`.
model.save("my_h5_model.h5")

# It can be used to reconstruct the model identically.
reconstructed_model = keras.models.load_model("my_h5_model.h5")

 

H5 파일은 Hierarchical Data Format (HDF) 5의 축약표현입니다. 보통 과학 데이터의 다차원 배열이 포함되기 때문에 다양한 과학분야(ex: 물리학, 공학, 딥러닝, ... 등)에서 주로 사용되는 파일형태입니다.

 

 

3-2. SavedModel 형태로 저장 또는 불러오기

# Calling `save('my_model')` creates a SavedModel folder `my_model`.
model.save("my_model")

# It can be used to reconstruct the model identically.
reconstructed_model = keras.models.load_model("my_model")

 

아래링크에서 SavedModel과 h5파일을 사용할 때 어떠한 차이가 있는지 기술해놓았으니 참고하시면 좋을 것 같습니다.

https://www.tensorflow.org/guide/keras/save_and_serialize?hl=ko 

 

Keras 모델 저장 및 로드  |  TensorFlow Core

소개 Keras 모델은 다중 구성 요소로 이루어집니다. 모델에 포함된 레이어 및 레이어의 연결 방법을 지정하는 아키텍처 또는 구성 가중치 값의 집합("모델의 상태") 옵티마이저(모델을 컴파일하여

www.tensorflow.org

 

 

 

3-3. Checkpoint

기존 tensorflow에서는 모델을 저장시키거나 불러올 때, SavedModel 방식 또는 Checkpoint 방식을 사용했습니다. Checkpoint에 대한 설명은 추후에 더 자세히 다루도록 하겠습니다. 아래링크에서 checkpoint에 관한 내용을 다루고 있으니 참고하시면 좋을 것 같습니다.

 

https://www.tensorflow.org/guide/checkpoint?hl=ko 

 

체크포인트 훈련하기  |  TensorFlow Core

Note: 이 문서는 텐서플로 커뮤니티에서 번역했습니다. 커뮤니티 번역 활동의 특성상 정확한 번역과 최신 내용을 반영하기 위해 노력함에도 불구하고 공식 영문 문서의 내용과 일치하지 않을 수

www.tensorflow.org

 

 

 

안녕하세요.

이번 글에서는 CNN 모델이 학습한 후 어떻게 성능을 평가하는지 알아보도록 하겠습니다.

 

우선 지금까지 배운 코드를 정리하면 아래와 같습니다.

 

 

##관련 모듈 import##

import os
from tensorflow import keras
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras import layers
from tensorflow import keras

 

 

##Data Load Code##

base_dir = './datasets/cats_and_dogs/'
train_dir = os.path.join(base_dir, 'train')
validation_dir = os.path.join(base_dir, 'validation')


train_datagen = ImageDataGenerator(
    featurewise_center=True,
    featurewise_std_normalization=True,
    rescale=1./255,
    rotation_range=20,
    width_shift_range=0.2,
    height_shift_range=0.2,
    horizontal_flip=True,
    validation_split=0.2)
 
 validation_datagen = ImageDataGenerator(rescale=1./255)
 
 
 train_generator = train_datagen.flow_from_directory(
        # 타깃 디렉터리
        train_dir,
        # 모든 이미지를 150 × 150 크기로 바꿉니다
        target_size=(150, 150),
        batch_size=32,
        # binary_crossentropy 손실을 사용하기 때문에 이진 레이블이 필요합니다
        class_mode='binary') #cats_and_dogs는 2개의 클래스만 있음
        
 validation_generator = validation_datagen.flow_from_directory(
        validation_dir,
        target_size=(150, 150),
        batch_size=32,
        class_mode='binary')
 

 

 

##CNN implementation by functional API##

input_shape = (150,150,3)
img_input = layers.Input(shape=input_shape)
output1 = layers.Conv2D(kernel_size=(3,3), filters=32, activation='relu')(img_input)
output2 = layers.MaxPooling2D((2,2))(output1)
output3 = layers.Conv2D(kernel_size=(3,3), filters=64, activation='relu')(output2)
output4 = layers.MaxPooling2D((2,2))(output3)
output5 = layers.Conv2D(kernel_size=(3,3), filters=128, activation='relu')(output4)
output6 = layers.MaxPooling2D((2,2))(output5)
output7 = layers.Conv2D(kernel_size=(3,3), filters=128, activation='relu')(output4)
output8 = layers.MaxPooling2D((2,2))(output7)
output9 = layers.Flatten()(output8)
output10 = layers.Dropout(0.5)(output9)
output11 = layers.Dense(512, activation='relu')(output10)
predictions = layers.Dense(2, activation='softmax')(output11)

model = keras.Model(inputs=img_input, outputs=predictions)

model.summary()

 

 

##Loss function, optimizer, learning rate schedule 설정

opt = SGD(lr=INIT_LR, momentum=0.9)
loss = CategoricalCrossentropy(label_smoothing=0.1)
model.compile(loss=loss, optimizer=opt, metrics=["accuracy"])

 

##Training 실행 코드##

train_step = train_generator.n // 32
valid_step = valid_generator.n // 32

history = model.fit_generator(
      train_generator,
      steps_per_epoch=train_step,
      epochs=30,
      validation_data=validation_generator,
      validation_steps=valid_step)

  • step_per_epoch: 한 epoch에 사용한 스텝 수를 지정합니다. 총 20000개의 training sample이 있고 batch size가 32이므로, 20000를 32로 나눈 몫(=20000/32=625)이 됩니다. (만약, 20001개의 training sample이 있다면 step_per_epoch은 "(20001//32)+1"이 되어야 합니다) 이러한 이유로 위의 train_step, valid_step을 아래와 같이 변경시켜주는 것이 좋습니다.
    • ex)총 45개의 훈련 샘플이 있고 배치사이즈가 3이라면 15 스텝(=step_per_epoch)으로 지정합니다.

 

  • validation_step: 한 epoch 종료 시 마다 검증할 때 사용되는 검증 스텝 수를 지정합니다.
    • ex) 총 15개의 validation 샘플이 있고 배치사이즈가 3이라면, validation_step을 5 스텝으로 지정합니다.

 

 

검은색: training sample/ 빨간색: validation sample

 

 

 

1. Metrics

딥러닝의 성능을 평가하기 위해 여러 성과지표(metrics)가 사용됩니다.

위에서 설명한 metrics은 accurcy로써 가장 대표적인 성과지표라 할 수 있습니다.

accuracy를 이용해 성과지표를 visualization하면 아래와 같이 표현할 수 있습니다.

 

import matplotlib.pyplot as plt

acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(len(acc))

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()

plt.figure()

plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()

plt.show()

 

 

 

Test dataset을 evaluation하려면 아래와 같이 코드를 작성해주면 됩니다. 

model.save('CNN_epoch_20.h5')

test_dir = os.path.join(base_dir, 'test')
test_datagen = ImageDataGenerator(rescale=1./255)
test_generator = test_datagen.flow_from_directory(
        test_dir,
        target_size=(150, 150),
        batch_size=32,
        class_mode='binary')

test_step = test_generator.n // 32

test_loss, test_acc = model.evaluate_generator(test_generator, steps=test_step, workers=4)
print(f'test loss : {test_loss:.4f} / test acc : {test_acc*100:.2f} %')

이미지 출처: https://junstar92.tistory.com/119

 

 

※loss function에 따라 metrics도 바뀔 수 있는 듯 합니다. (예전에 사용할 때 loss function을 categorical_crossentropy를 사용했을 때, 그냥 metrics를 accuracy로 해도 문제가 없었던것 같은데 나중에 바꿔서 써봐야겠네요)

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['sparse_categorical_accuracy'])

 

 

 

 

2. Keras and Tensorflow backend metrics

모델 컴파일(model.compile) 할 때, Backend 엔진이 tensorflow(=tf)인 경우 몇 가지 기본 성과지표(ex: recall, precision 등을 제공해줍니다)

 

https://www.tensorflow.org/api_docs/python/tf/keras/metrics

 

Module: tf.keras.metrics  |  TensorFlow Core v2.5.0

Built-in metrics.

www.tensorflow.org

 

 

Keras tensorflow backend기반의 다양한 metrics 코드 구현 관련 내용은 아래 링크를 참고해주세요!

 

https://www.tensorflow.org/tutorials/structured_data/imbalanced_data?hl=ko 

 

불균형 데이터 분류  |  TensorFlow Core

이 튜토리얼에서는 한 클래스의 예시의 수가 다른 클래스보다 훨씬 많은 불균형 데이터세트를 분류하는 방법을 소개합니다. Kaggle에서 호스팅 되는 신용 카드 부정 행위 탐지 데이터세트를 사용

www.tensorflow.org

 

 

3. Keras and other backend metrics

 

하지만, Keras 2버전 부터는 tensorflow backend가 아니라면 아래 링크에서 제공되는 metrics를 제외하고서는 전부 사용자 정의 함수로 구현해주어야 합니다.

https://keras.io/ko/metrics/

 

Metrics - Keras Documentation

측정항목의 사용법 측정항목은 모델의 성능을 평가하는데 사용되는 함수입니다. 측정항목 함수는 모델이 컴파일 될 때 metrics 매개변수를 통해 공급됩니다. model.compile(loss='mean_squared_error', optimize

keras.io

 

 

실제로 Keras 2에서 precision, recall, fmeasure 등과 같은 metrics는 따로 구현해야 한다고 언급하고 있네요. 

 

"Several legacy metric functions have been removed, namely matthews_correlation, precision, recall, fbeta_score, fmeasure."

 

https://github.com/keras-team/keras/wiki/Keras-2.0-release-notes

 

keras-team/keras

Deep Learning for humans. Contribute to keras-team/keras development by creating an account on GitHub.

github.com

 

 

Keras기반의 사용자 정의 함수(metrics) 코드 구현 관련 내용은 아래 링크를 참고해주세요!

https://neptune.ai/blog/keras-metrics

 

Keras Metrics: Everything You Need To Know - neptune.ai

Keras metrics are functions that are used to evaluate the performance of your deep learning model. Choosing a good metric for your problem is usually a difficult task. you need to understand which metrics are already available in Keras and tf.keras and h

neptune.ai

 

 

 

 

[Reference Site]

 

https://nbviewer.jupyter.org/github/rickiepark/deep-learning-with-python-notebooks/blob/tf2/5.2-using-convnets-with-small-datasets.ipynb

 

Jupyter Notebook Viewer

이제 2,000개의 훈련 이미지, 1,000개의 검증 이미지, 1,000개의 테스트 이미지가 준비되었습니다. 분할된 각 데이터는 클래마다 동일한 개수의 샘플을 포함합니다. 균형잡힌 이진 분류 문제이므로

nbviewer.jupyter.org

 

 

https://junstar92.tistory.com/119

 

[Tensorflow][Kaggle] Cats vs. Dogs Classification(수정 : 2020-12-07)

www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition Dogs vs. Cats Redux: Kernels Edition Distinguish images of dogs from cats www.kaggle.com 딥러닝 연습으로 Kaggle의 Dogs vs. Cats Classification을..

junstar92.tistory.com

 

https://m.blog.naver.com/wideeyed/221226716255

 

[Keras] 2.0에서 precision,recall 사용하기

tf.keras.metrics를 통해 precision, recall을 지원하므로 사용한다. 다른 Backend엔진을 사용하거나 더 ...

blog.naver.com

 

안녕하세요.

앞서 CNN 구조를 구성했다면 최종적으로 model.compile 함수를 이용하여 해당 모델에 적용할 loss function, optimizer, metrics등을 설정해주어야 합니다.

from tensorflow.keras import layers
from tensorflow import keras
from tensorflow.keras import optimizers

###CNN 모델 구축###
input_shape = (150,150,3)
img_input = layers.Input(shape=input_shape)
output1 = layers.Conv2D(kernel_size=(3,3), filters=32, activation='relu')(img_input)
output2 = layers.MaxPooling2D((2,2))(output1)
output3 = layers.Conv2D(kernel_size=(3,3), filters=64, activation='relu')(output2)
output4 = layers.MaxPooling2D((2,2))(output3)
output5 = layers.Conv2D(kernel_size=(3,3), filters=128, activation='relu')(output4)
output6 = layers.MaxPooling2D((2,2))(output5)
output7 = layers.Conv2D(kernel_size=(3,3), filters=128, activation='relu')(output4)
output8 = layers.MaxPooling2D((2,2))(output7)
output9 = layers.Flatten()(output8)
output10 = layers.Dropout(0.5)(output9)
output11 = layers.Dense(512, activation='relu')(output10)
predictions = layers.Dense(2, activation='softmax')(output11)

model = keras.Model(inputs=img_input, outputs=predictions)

###Loss, optimizer, metrics 설정###
model.compile(loss='binary_crossentropy',
              optimizer=optimizers.RMSprop(lr=1e-4),
              metrics=['accuracy'])

 

이번 글에서는 model.compile에 적용되는 loss, optimizer, metrics 들에 대해 좀 더 자세히 알아보도록 하겠습니다.

 

 

 

 

 

1. Loss

1-1. 기본 Loss function

Tensorflow2는 아래링크에서 볼 수 있듯이 기본적인  loss function을 제공해줍니다.

https://www.tensorflow.org/api_docs/python/tf/keras/losses

 

Module: tf.keras.losses  |  TensorFlow Core v2.5.0

Built-in loss functions.

www.tensorflow.org

 

Loss function을 적용하는 방식은 크게 두 가지 입니다.

 

첫 번째 방식. compile 함수에 있는 loss 속성에 특정 loss를 기재

model.compile(loss='binary_crossentropy',
              optimizer=optimizers.RMSprop(lr=1e-4),
              metrics=['accuracy'])

 

두 번째 방식. loss instance 생성 후, compile 함수에 있는 loss 속성에 앞서 생성한 loss instance를 기재 

loss = CategoricalCrossentropy()
model.compile(loss=loss, optimizer='adam', metrics=["accuracy"])

 

Q. tf.keras.losses 부분 보면 bianry_crossentropy는 function이고, BinaryCrossentropy는 class로 되어 있는데, 이 두 가지가 어떤 차이가 있는지 모르겠네요. 어느 사이트 보면 function으로 선언한 경우 accuracy가 더 떨어져서 나온다는 말도 있는데, 정확히 어떤 차이가 있는건지...

 

 

 

1-2. 세 가지 기본 Loss function 소개

앞서 tensorflow에서 제공한 기본 loss 함수 중에, 딥러닝 분류 목적으로 사용하는 대표적인 loss function은 3가지 입니다.

 

1) Binary Crossentropy

Tensorflow에서 제공하는 BinaryCrossentropy는 2가지의 클래스를 구분하는 task에 적용할 수 있는 함수입니다.   

이미지 출처: https://gombru.github.io/2018/05/23/cross_entropy_loss/

 

 

 

2) Categorical Crossentropy

3개 이상의 클래스를 classification 할 경우 우리는 이를 multiclassification이라고 합니다.

이 경우에는 tensorflow에서 제공하는 CategoricalCrossentropy를 적용해주어야 합니다.

이미지 출처: https://gombru.github.io/2018/05/23/cross_entropy_loss/

 

 

3) SparseCategorical Crossentropy

10개의 클래스를 분류한다고 한다는 가정하에 아래 그림에 있는 기호를 간단히 표현하면 다음과 같습니다.

  • t → label=answer → [0, 0, 0, 0, 0, 1, 0, 0, 0, 0]
  • y → probability = predict → [0.1, 0.05, 0.05, 0.1, 0.1, 0.3, 0.1, 0.05, 0.05, 0.1]

아래의 CategoricalCrossentropy 수식을 보면 사실 6번째 해당하는 class를 제외하면 모든 t는 0이기 때문에 loss function에 아무런 영향도 미치지 않습니다. 사실상 6번째에 해당하는 t, y 값만 고려해주고 나머지는 무시해줘도 되는 것이죠. 

 

예를 들어, if 문을 이용하여 정답에 해당하는 label에 대해서만 "loss=-t×log(y)" 를 적용해주면 속도도 더 빨라지게 되는데, 이러한 방식의 loss function을 SparseCategoricalCrossentropy 라고 합니다. (실제로 DNN을 hardcoding 했을 때, CategoricalCrossentropy와 SparseCategoricalCrossentropy 학습 결과에는 변함이 없었습니다. 또한, 실제로 돌려보면 SparseCategoricalCrossentropy 방식으로 hardcoding 했을 때 좀 더 학습 속도가 빨랐습니다)

 

 

 

 

1-3. Label smoothing

Tensorflow 기본 loss API에서는 label smoothing을 쉽게 적용할 있게 구현해 놨습니다. 

 

loss = CategoricalCrossentropy(label_smoothing=0.1)
model.compile(loss=loss, optimizer='adam', metrics=["accuracy"])

 

For example, if 0.1, use (0.1 / num_classes) for non-target labels and (0.9 + (0.1 / num_classes)) for target labels. (참고로 non-target labels의 확률값은 uniform distribution을 따릅니다)

이미지 출처: https://towardsdatascience.com/label-smoothing-make-your-model-less-over-confident-b12ea6f81a9a

 

 

참고로 앞서 설명한 SparseCategoricalCrossentropy의 기본전제는 hard label이기 때문에, label smoothing 속성이 왜 없는지 쉽게 파악할 수 있습니다.

  • hard label: 실제 정답외에 모든 label 값은 0으로 설정하는 방식

 

 

1-4. Extra loss functions by Tensorflow addons

Tensorflow 기본 loss API외에 SIG라는 곳에서 추가적인 loss function 들을 구현해 tensorflow에 contribution하고 있습니다. 예를 들어, 최근에 contrastive loss 도 주목을 받고 있는데, 이러한 loss를 Tensorflow Addons (by SIG) 에서 제공하는 API를 이용해 사용할 수 있습니다.

 

https://www.tensorflow.org/addons/api_docs/python/tfa/losses

 

Module: tfa.losses  |  TensorFlow Addons

Additional losses that conform to Keras API.

www.tensorflow.org

 

 

 

 

 

1-5. Custom Loss function

우리가 사용할 loss function이 앞서 소개된 기본 loss function에 없다면 우리가 스스로 만들어야 합니다.

 

대부분 정해진 task에 의해 기본적인 loss function을 쓰는 것이 보편적이지만, 종종 자신만의 loss function을 만들어 사용하는 경우도 있습니다. 예를 들어, Semi-supervised loss function, focal loss function과 같은 경우는 tensorflow에서 기본적으로 제공되는 loss function이 아니기 때문에 사용자가 직접 함수를 만들어 사용해야 합니다.

 

예를 들어, hubber loss라는 것을 만들어 사용하려면 아래와 같이 작성해주면 됩니다.

def my_huber_loss(y_true, y_pred):
	threshold = 1
	error = y_true - y_pred
	is_small_error = tf.abs(error) <= threshold
	small_error_loss = tf.square(error) / 2
	big_error_loss = threshold * (tf.abs(error) - (0.5 * threshold))
	return tf.where(is_small_error, small_error_loss, big_error_loss)
    
    
model.compile(optimizer='sgd', loss='my_huber_loss')


(↓↓huber loss 수식 설명↓↓)

https://mypark.tistory.com/14?category=1007621 

 

[Tensorflow 2][Keras] Week 2 - Custom loss functions

본 포스팅은 다음 과정을 정리 한 글입니다. Custom Models, Layers, and Loss Functions with TensorFlow www.coursera.org/specializations/tensorflow-advanced-techniques 지난 시간 리뷰 2021.03.13 - [Artif..

mypark.tistory.com

 

 

 

 

 

2. Optimizer

2-1. 기본 optimizer

Tensorflow2는 아래링크에서 볼 수 있듯이 기본적인 Optimizer를 제공해줍니다.

https://www.tensorflow.org/api_docs/python/tf/keras/optimizers

 

Module: tf.keras.optimizers  |  TensorFlow Core v2.5.0

Built-in optimizer classes.

www.tensorflow.org

 

위링크에서 자신이 적용시키고 싶은 optimizer를 클릭하면 해당 optimizer에 어떤 속성들(ex: learning rate, etc...)이 있는지 알 수 있습니다.

 

 

 

 

optimizer도 아래와 같이 두 가지 패턴으로 선언이 가능합니다.

 

첫 번째 방식

model.compile(loss='binary_crossentropy',
              optimizer=optimizers.RMSprop(lr=1e-4),
              metrics=['accuracy'])

 

두 번째 방식

opt = SGD(lr=INIT_LR, momentum=0.9)
loss = CategoricalCrossentropy(label_smoothing=0.1)
model.compile(loss=loss, optimizer=opt, metrics=["accuracy"])

 

 

2-2. Extra optimizers by Tensorflow addons

앞서 loss functionn에서 언급한 것 처럼, 기본 tensorflow API에서 제공되는 optimizer 외에 SIG에서 제공하는 다양한 optimizer들이 있습니다.

(↓↓supported by SIG↓)

https://www.tensorflow.org/addons/api_docs/python/tfa/optimizers

 

Module: tfa.optimizers  |  TensorFlow Addons

Additional optimizers that conform to Keras API.

www.tensorflow.org

 

 

 

 

2-3. 최신 optimizer

앞서 제공한 기본적인 optimizer 외에도 현재 개발중인 다양한 optimizer들이 등장하고 있습니다. 예를 들어, 작년에 NeurIPS에서 Adabelief라는 optimizer를 발표한바 있습니다.

https://arxiv.org/abs/2010.07468

 

AdaBelief Optimizer: Adapting Stepsizes by the Belief in Observed Gradients

Most popular optimizers for deep learning can be broadly categorized as adaptive methods (e.g. Adam) and accelerated schemes (e.g. stochastic gradient descent (SGD) with momentum). For many models such as convolutional neural networks (CNNs), adaptive meth

arxiv.org

 

 

보통 이런 최신 optimizer는 논문이 나오면 github에 등록하여 일반 사용자들이 쉽게 사용할 수 있도록 기록해놓습니다. 

https://github.com/juntang-zhuang/Adabelief-Optimizer

 

juntang-zhuang/Adabelief-Optimizer

Repository for NeurIPS 2020 Spotlight "AdaBelief Optimizer: Adapting stepsizes by the belief in observed gradients" - juntang-zhuang/Adabelief-Optimizer

github.com

 

 

위의 사이트에 접속하면 아래와 같이 tensorflow에서 어떻게 사용하면 되는지 설명되어 있습니다.

이미지 출처: https://github.com/juntang-zhuang/Adabelief-Optimizer

 

 

아래 글을 보면 tensorflow 기반의 keras 에서는 호환이 안된다고 했는데, 

https://github.com/juntang-zhuang/Adabelief-Optimizer/issues/2

 

Tensorflow implementation doesn't work · Issue #2 · juntang-zhuang/Adabelief-Optimizer

TF 2.3 from tensorflow.keras.layers import Dense from tensorflow.keras.models import Sequential import numpy as np from adabelief_tf import AdaBeliefOptimizer x = np.random.random_sample((5,)) y = ...

github.com

 

 

"Make it compatiable with tensorflow and keras"라는 부분을 검색해보면 해당 부분이 수정된 것으로 보입니다 (아직 적용해보지 않아 실제로 잘 동작하는지 아닌지는 확인해봐야합니다 (Pytorch 버전은 잘 돌아가네요).

 

 

 

 

2-4. Learning rate schedule

학습이 진행 될 수록 점점 global minimum에 접근한다고 가정했을 때, learning rate도 천천히 줄여주는 것이 학습에 효과적이라고 알려져있습니다. 즉, schedule대로 learning rate를 변경해가며 사용하는 것이죠.

 

예를 들어, 위의 이미지에서는 exponential learning rate decay 방식을 표현하고 있는데, 이를 tensorflow 2 코드로 적용시키면 아래와 같습니다.

initial_learning_rate = 0.1
lr_schedule = keras.optimizers.schedules.ExponentialDecay(
    initial_learning_rate,
    decay_steps=100000,
    decay_rate=0.96,
    staircase=True)

optimizer = keras.optimizers.RMSprop(learning_rate=lr_schedule)

 

Tensorflow 2에서는 "opimizer.schedules"을 통해 여러 learning rate decay 기법을 제공해줍니다.

https://www.tensorflow.org/api_docs/python/tf/keras/optimizers/schedules

 

Module: tf.keras.optimizers.schedules  |  TensorFlow Core v2.5.0

Public API for tf.keras.optimizers.schedules namespace.

www.tensorflow.org

 

예를 들어, CosineAnnealing 방식을 적용하고 싶다면 아래와 같이 코드를 작성해주면 됩니다.

tf.keras.optimizers.schedules.CosineDecayRestarts(
    initial_learning_rate, first_decay_steps, t_mul=2.0, m_mul=1.0, alpha=0.0,
    name=None
)
  • initial_learning_rate : 최초의 학습률
  • first_decay_steps : (첫 주기의 감쇄가 진행되는 총 스텝 수) 최초의 주기 길이
  • t_mul : 주기 T를 늘려갈 비율 (첫 주기가 100step이면 그 다음은 200step, 그 다음은 400step...)
  • m_mul : 최초 학습률로 설정한 값에 매 주기마다 곱해줄 값 (0.9라면 매 주기 시작마다 initial_learning_rate에 (i는 주기 인덱스)만큼 곱한 값을 주기 시작 학습률로써 사용한다.)
  • alpha : 학습률의 하한을 설정하기위한 파라미터로 학습률의 감소 하한은 initial_learning_rate * alpha가 된다.
  • 레퍼런스 사이트

이미지 출처: https://www.programmersought.com/article/96553631082/

 

 

 

 

(↓↓↓위에서 언급한 learning rate decay 구현 및 시각화한 사이트↓↓↓)

https://www.programmersought.com/article/96553631082/

 

The tricks of learning rate decay in Tensorflow - Programmer Sought

The method of parameter update in deep learning must be very clear to everyone-sgd, adam, etc., and the discussion about which is better is also extensive. but,learning rate decay strategyHas anyone paid special attention? When training neural networks, th

www.programmersought.com

 

 

2-4. Learning rate warm-up

※Learning rate warm-up도 굉장히 자주쓰이는 트릭인데, tensorflow에서 기본적으로 제공해주는 방식은 없는 듯합니다. Github에서 다운받거나 아래 사이트를 참고하여 직접구현해주면서 사용해야 할 듯 합니다 (Pytorch는 굉장히 쉽게 사용할 수 있게 되어 있는데, tensorflow로 쓰려니 참...)

(↓↓↓아래 사이트에서 learning rate warm up 코드 부분을 참고해주세요!↓↓↓)

https://www.dlology.com/blog/bag-of-tricks-for-image-classification-with-convolutional-neural-networks-in-keras/

 

Bag of Tricks for Image Classification with Convolutional Neural Networks in Keras | DLology

Posted by: Chengwei 2 years, 6 months ago (Comments) This tutorial shows you how to implement some tricks for image classification task in Keras API as illustrated in paper https://arxiv.org/abs/1812.01187v2. Those tricks work on various CNN models like

www.dlology.com

 

 

지금까지 model.compile의 속성들 중인 loss function, optimizer, learning rate schedule 에 대해서 살펴보았습니다.

 

다음 글에서는 마지막 남은 속성인 metrics에 대해 소개하도록 하겠습니다.

안녕하세요. 

이번에는 tensorflow 2 기반으로 CNN 모델을 구현하는 내용을 다루도록 하겠습니다.

Tensorflow 2에서 DNN or CNN 모델을 구축하는 방식은 크게 2가지로 나눌 수 있습니다.

  1. Sequential API
  2. Functional API

먼저, sequential API에 대해 설명한 후, functional API를 설명하도록 하겠습니다.

 

 

1. Sequential API

  • Sequential API는 tensorflow 2에서 뉴럴 네트워크를 가장 쉽게 구성할 수 있는 방식입니다.
  • Sequential이라는 이름에 맞게 add 함수를 이용하면 layer가 순차대로 연결이 됩니다.
  • A sequential model is appropriate for a plain stack of layers where each layer has exactly one input tensor and one output tensor.
    • 즉, add 함수를 통해 각 layer들은 정확히 하나의 input값만을 받을 수 있으며, output또한 하나의 tensor 형태로만 출력이 가능합니다.
    • 이러한 특징이 갖고 있는 단점 중 하나는 복잡한 CNN 모델을 구성하기 힘들다는 점입니다.
    • 예를 들어, ResNet 같은 경우는 Residual block 을 구성하기 위해서는 두개의 input 값 (ex: F(x), x)을 받아야 하는데, Sequential API로 구성하는 경우 x값을 받을 수 없으니 ResNet 모델을 구현할 수 없게 됩니다. 
    • 위와 같은 이유로 DenseNet 또한 구현이 불가능 합니다.

from tensorflow.keras import layers
from tensorflow.keras import models

#Conv2D(채널 수, (Conv filter 크기), activation function, 입력 데이터 크기)

model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu',
                        input_shape=(150, 150, 3))) 
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Flatten())
model.add(layers.Dropout(0.5))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

 

 

 

2. Functional API

  • Functional API을 이용하면 다양한 input 값을 받을 수 있습니다.
  • 즉, layer에 input 값을 따로 기재해줄 수 있다는 뜻이죠.
from tensorflow.keras import layers
from tensorflow import keras

input_shape = (150,150,3)
img_input = layers.Input(shape=input_shape)
output1 = layers.Conv2D(kernel_size=(3,3), filters=32, activation='relu')(img_input)
output2 = layers.MaxPooling2D((2,2))(output1)
output3 = layers.Conv2D(kernel_size=(3,3), filters=64, activation='relu')(output2)
output4 = layers.MaxPooling2D((2,2))(output3)
output5 = layers.Conv2D(kernel_size=(3,3), filters=128, activation='relu')(output4)
output6 = layers.MaxPooling2D((2,2))(output5)
output7 = layers.Conv2D(kernel_size=(3,3), filters=128, activation='relu')(output4)
output8 = layers.MaxPooling2D((2,2))(output7)
output9 = layers.Flatten()(output8)
output10 = layers.Dropout(0.5)(output9)
output11 = layers.Dense(512, activation='relu')(output10)
predictions = layers.Dense(2, activation='softmax')(output11)

model = keras.Model(inputs=img_input, outputs=predictions)

 

 

3. Functional API를 이용해 Residual block 구성하기

  • BatchNormalization layer 추가
  • skip connection 적용

input = X
#첫 번째 conv layer에 있는 residual block
block_1_output1 = layers.Conv2D(kernel_size=(3,3), filters=channel_num, padding='same', name=name + '0_conv')(input)
block_1_output2 = BatchNormalization(name=name + '0_bn')(block_1_output1)
block_1_output3 = Activation('relu', name=name + '0_relu')(block_1_output2)
block_1_output4 = Conv2D(kernel_size=(3, ), filters=channel_num, padding='same', name=name + '1_conv')(block_1_output3)
# Zero gamma - Last BN for each ResNet block, easier to train at the initial stage.
#block_1_output4 = F(X)
block_1_output4 = BatchNormalization(gamma_initializer='zeros', name=name + '1_bn')(block_1_output4)
#merge_data = X+F(X)
merge_data = add([block_1_output4, input], name=name + '1_add') 
out = Activation('relu', name=name + '2_conv')(merge_data)

 

위의 코드는 아래 이미지의 original 버전이라고 생각하시면 됩니다. 위의 코드를 기반으로 나머지 구조들((b), (c), (d), (e))도 구현하실 수 있겠죠?

 

 

 

 

3. Model summary

앞서 CNN 모델을 작성했다면, 해당 모델에 대한 간단한 구조를 summary 함수를 통해 알아볼 수 있습니다.

model.summary()

 

위의 출력결과에서는 "Non-trainable params:0"으로 표현되어 있는데, 나중에 transfer learning or fine-tuning을 적용시킬 때는 특정 layer까지 freezing 시키는 경우도 빈번하므로 Non-trainable params가 0이 아닐 때도 생깁니다. 이 부분은 trasnfer learning을 다룰 때 설명하도록 하겠습니다.

 

CNN모델을 학습시킬 때, 가장먼저 해야할 것은 train, validation, test dataset을 load하는 것입니다.

이번 장에서는 내가 구축한 (custom) dataset을 load하는 방식에 대해서 알아보도록 하겠습니다.

 

 

1. Custom dataset directory 설정

1) 학습데이터는 이미지 파일이므로 파일데이터와 관련된 module를 import합니다.

  • OS 모듈은 환경 변수나 디렉터리, 파일 등의 OS 자원을 제어할 수 있게 해주는 모듈
import os

 

 

2)학습할 데이터셋을 세팅합니다.

우선 학습할 데이터를 다운받고 아래와 같이 세팅이 되어 있는지 확인해 줍니다.

기본적으로 학습을 위한 데이터(cat_and_dogs)는 아래와 같이 train, validation, test 데이터 셋으로 구성이 되어있습니다. 

base_dir 경로

 

train, validation, test 데이터셋(폴더)에는 각각 클래스와 관련된 폴더가 있고, 해당 폴더에 실제 이미지 데이터가 위치합니다. cats_and_dogs 분류문제는 개와 고양이 두 클래스를 구분하는 binary classification 문제이므로, 각 폴더에 2개의 클래스(개, 고양이)가 포함되어 있습니다.

train_dir 경로

 

!! 주석부분에 폴더 정보들을 기록해놨으니 꼭 확인해 주세요 !!

#base_dir → 다운받은 원본 데이터셋 경로 = 모든 training, validation, test 데이터셋이 포함되어 있음
#cats_and_dogs에 있는 총 이미지 데이터 개수 = 25,000 ← training:20,000 + validation:4,000 + test:500
base_dir = './datasets/cats_and_dogs/'

#train_dir → 원본 데이터셋의 학습 데이터 경로 = 모든 class(개, 고양이)들의 이미지들이 포함되어 있음
#train_dir에 있는 총 이미지 데이터 개수 = 20,000 ← 강아지=10,000 + 고양이=10,000
train_dir = os.path.join(base_dir, 'train')  #train_dir = './datasets/cats_and_dogs/train'

#validation_dir → 원본 데이터셋의 학습 데이터 경로 = 모든 class(개, 고양이)들의 이미지들이 포함되어 있음
#validation_dir에 있는 총 이미지 데이터 개수 = 4,000 ← 강아지=2,000 + 고양이=2,000
validation_dir = os.path.join(base_dir, 'validation')  #validation_dir = './datasets/cats_and_dogs/validation'

#test_dir → 원본 데이터셋의 학습 데이터 경로 = 모든 class(개, 고양이)들의 이미지들이 포함되어 있음
#test_dir에 있는 총 이미지 데이터 개수 = 1,000 ← 강아지=500 + 고양이=500
test_dir = os.path.join(base_dir, 'test')  #test_dir = './datasets/cats_and_dogs/test'

 

 

 

2. Preprocessing (Normalization)

아래 링크에 걸어둔 글에서 볼 수 있듯이, 보통 효율적인 학습을 위해 딥러닝의 학습데이터들은 전처리의 일환으로 normalization이 적용됩니다

https://89douner.tistory.com/42?category=868069 

 

8. 데이터 전처리 (Data Preprocessing and Normalization)

Q. DNN을 학습시키기 전에 왜 데이터를 전처리해주어야 하나요? 안녕하세요~ 이번시간에는 DNN 모델이 학습을 효율적으로 하기위해 필요한 정규(Noramlization; 정규화) 대해서 알아보도록 할거에요~

89douner.tistory.com

 

 

간단하게 말하자면, normalization이 적용된 학습데이터의 problem space가 더 안정적으로 형성될 수 있으므르로 학습이 더 수월하게 된다는 이점이 있습니다.

 

 

위와 같은 normalization을 적용해주기 위해서는 아래와 같이 zero center를 맞춰준후, data를 normalization 해주어야 합니다.

 

위와 같이 "zero-center→normalization"을 적용시켜주려면 아래와 같은 순서를 따르면 됩니다.

  1. Zero center: 모든 데이터들의 평균을 구한다 → 모든 데이터들 각각에 해당 평균 값을 빼준다.
  2. Normalization: 모들 데이터들의 표준편차를 구한다 → 모든 데이터들 각각에 해당 표준편차 값을 나눠준다.

이미지 출처: https://www.kdnuggets.com/2020/04/data-transformation-standardization-normalization.html

 

위와 같은 데이터 전처리를 이미지에 적용할 때, 가능한 2가지 경우의 수가 있습니다.

 

2-1) 하나의 이미지 데이터를 기반으로 normalization 적용하기

예를 들어, 224×224×3 이미지가 있다고 가정해보겠습니다. 하나의 pixel에는 0~255값들이 들어 있는데, 앞에서 언급한 이미지 크기를 기준으로 한다면 150528(=224×224×3) pixel들이 존재하게 됩니다. 

 

이미지 출처: http://openframeworks.kr/ofBook/chapters/image_processing_computer_vision.html

 

즉, 하나의 이미지에 해당하는 고유의 평균 및 표준편차 값을 구할 수 있기 때문에, 하나의 데이터에만 normalization을 적용할 수 있게 됩니다. 예를 들어, 150528(=224×224×3) 개의 pixel값들을 기반으로 평균 및 표준편차 값을 구하고, 모든 pixel에 평균값을 빼준후 표준편차값을 나눠주게 됩니다.

 

Keras API에서 의 설명을 보면 알 수 있듯이, 하나의 이미지당 normalization을 적용시키려면 samplewise 속성을 이용하면 됩니다.

  • samplewise_center: Boolean. Set each sample mean to 0.
  • samplewise_std_normalization: Boolean. Divide each input by its std.
tf.keras.preprocessing.image.ImageDataGenerator(
    samplewise_center=True,
    samplewise_std_normalization=True
)

 

 

(↓↓↓Keras Image data Preprocessing API: ex) ImageDataGenerator↓↓↓)

https://keras.io/api/preprocessing/image/

 

Keras documentation: Image data preprocessing

Image data preprocessing image_dataset_from_directory function tf.keras.preprocessing.image_dataset_from_directory( directory, labels="inferred", label_mode="int", class_names=None, color_mode="rgb", batch_size=32, image_size=(256, 256), shuffle=True, seed

keras.io

 

 

 

2-2) 모든 이미지 데이터를 기반으로 normalization 적용하기

이번에는 하나의 이미지가 아닌 batch 단위로 묶인 이미지들을 기반으로 하여 해당 평균 및 표준편차 값을 구한 뒤, normalization을 적용 시키는 방식입니다. (사실, 전체 학습 이미지에 대한 평균 및 표준편차 값을 구하는건지 아닌지 모르겠으나 해당 API에서 "The data will be looped over (in batches)."라고 기술된 부분을 보고 'batch 단위로 평균 및 표준편차 값이 구해지겠구나'라고 추정했습니다. 혹시 아니면 알려주시면 감사하겠습니다)

 

예를 들어 batch가 4라고 하면, 224×224×3×4 개의 pixel값들을 기반으로 평균 및 표준편차 값을 구하고, 모든 pixel에 평균값을 빼준후 표준편차값을 나눠주게 됩니다.

 

Keras API에서 의 설명을 보면 알 수 있듯이, batch 이미지당 normalization을 적용시키려면 featurewise 속성을 이용하면 됩니다.

tf.keras.preprocessing.image.ImageDataGenerator(
    featurewise_center=True,
    featurewise_std_normalization=True
)
  • featurewise_center: Boolean. Set input mean to 0 over the dataset, feature-wise.
  • featurewise_center: Boolean. Set input mean to 0 over the dataset, feature-wise.

 

아래 API를 보면 featurewise와 samplewise 관련 속성은 모두 False로 적용되어 있는걸 확인할 수 있다.

(↓↓↓Tensorflow 2 API 에서 ImageDataGenerator ↓↓↓)

https://www.tensorflow.org/api_docs/python/tf/keras/preprocessing/image/ImageDataGenerator

 

tf.keras.preprocessing.image.ImageDataGenerator

Generate batches of tensor image data with real-time data augmentation.

www.tensorflow.org

 

 

Q. DNN에서 봤을 때는 이러한 것이 많은 도움이 되는걸 이론적으로 확인할 수 있습니다. 그런데, 개인적으로 pytorch 기반으로 작성하여 CNN에 적용시켰을 때는 적용을 하나 안하나 큰 차이가 없었던 것 같습니다. 다른 분야에서는 어떻게 적용하고 있는지 궁금하네요. 

 

 

3. Data augmentation

CNN은 굉장히 다양한 data augmentation 기법을 지원합니다.

따라서 분류하려는 대상에 따라 적절한 data augmentation 기법을 적용시키면 됩니다.

예를 들어, Chest X-ray 같은 경우는 90도 rotation 해서 evaluation 하는 경우는 없으니, 90도 rotation은 적용시키지 않아도 되겠죠?

 

아래 코드에서 rescale은 overfitting을 방지하고자 모든 pixel 값들을 0~1 범위로 normalization 해주는 것인데, 앞서 "2. Preprocessing (Normalization)"에서 언급한 것과 같은 목적으로 적용된 것이라 생각하시면 될 것 같습니다.

tf.keras.preprocessing.image.ImageDataGenerator(
    featurewise_center=True,
    featurewise_std_normalization=True,
    zca_whitening=False,
    zca_epsilon=1e-06,
    rotation_range=0,
    width_shift_range=0.0,
    height_shift_range=0.0,
    brightness_range=None,
    shear_range=0.0,
    zoom_range=0.0,
    channel_shift_range=0.0,
    fill_mode="nearest",
    cval=0.0,
    horizontal_flip=False,
    vertical_flip=False,
    rescale=1./255
)

 

(↓↓↓위에서 언급한 data augmentation 중 몇 가지 예시↓↓↓)

https://theailearner.com/2019/07/06/data-augmentation-with-keras-imagedatagenerator/

 

Data Augmentation with Keras ImageDataGenerator

One of the methods to prevent overfitting is to have more data. By this, our model will be exposed to more aspects of data and thus will generalize better. To get more data, either you manually col…

theailearner.com

 

Q. rescaling=./255를 먼저 해주고, feature_wise or sample_wise같은 normalization을 적용을 해주는건지, 아니면 그 반대순서로 적용을 해주는건지 모르겠네요....

 

 

4. 총정리: Data Load

지금까지 배운 내용을 토대로 data load 코드를 작성하면 아래와 같습니다.

import os
from tensorflow import keras
from tensorflow.keras.preprocessing.image import ImageDataGenerator

base_dir = './datasets/cats_and_dogs/'
train_dir = os.path.join(base_dir, 'train')
validation_dir = os.path.join(base_dir, 'validation')


train_datagen = ImageDataGenerator(
    featurewise_center=True,
    featurewise_std_normalization=True,
    rescale=1./255,
    rotation_range=20,
    width_shift_range=0.2,
    height_shift_range=0.2,
    horizontal_flip=True,
    validation_split=0.2)
 
 validation_datagen = ImageDataGenerator(rescale=1./255)
 
 
 train_generator = train_datagen.flow_from_directory(
        # 타깃 디렉터리
        train_dir,
        # 모든 이미지를 150 × 150 크기로 바꿉니다
        target_size=(150, 150),
        batch_size=32,
        # binary_crossentropy 손실을 사용하기 때문에 이진 레이블이 필요합니다
        class_mode='binary') #cats_and_dogs는 2개의 클래스만 있음
        
 validation_generator = validation_datagen.flow_from_directory(
        validation_dir,
        target_size=(150, 150),
        batch_size=32,
        class_mode='binary')
 

 

위와 같이 코드를 세팅해주면 학습을 시켜주기 위한 data loader 과정이 마무리 됩니다.

이후 아래 코드를 실행시켜주면 학습이 진행됩니다.

아래 코드는 다음 글에서 설명하도록 하겠습니다.

from tensorflow.keras import layers
from tensorflow.keras import models
from tensorflow.keras import optimizers

model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu',
                        input_shape=(150, 150, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Flatten())
model.add(layers.Dropout(0.5))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

model.compile(loss='binary_crossentropy',
              optimizer=optimizers.RMSprop(lr=1e-4),
              metrics=['accuracy'])

 

 

※보통 cifar10, mnist, fashion mnist와 같은 적은 양의 데이터셋은 아래 링크에 기재된 tensorflow.keras.datasets 에서 제공을 해줍니다. 하지만, ImageNet 같은 경우는 데이터양이 워낙 방대하여 직접다운로드 받고 학습을 위한 구조를 세팅해주고 학습시켜야 한다는점 알아두시면 좋을것 같습니다!

 

https://www.tensorflow.org/api_docs/python/tf/keras/datasets

 

Module: tf.keras.datasets  |  TensorFlow Core v2.5.0

Small NumPy datasets for debugging/testing.

www.tensorflow.org

 

 

 

Tensorflow 기반 CNN 구현 코드는 아래 사이트들을 참고했습니다.

 

 

(5장→CNN)

https://github.com/rickiepark/deep-learning-with-python-notebooks/tree/tf2

 

rickiepark/deep-learning-with-python-notebooks

<케라스 창시자에게 배우는 딥러닝> 도서의 주피터 노트북. Contribute to rickiepark/deep-learning-with-python-notebooks development by creating an account on GitHub.

github.com

 

+ Recent posts