Data Science/Deep Learning

3. 데이터 증강기법 (Data Augmentation)

HJChung 2020. 5. 10. 23:30

CNN은 영상의 2차원 변환인 회전(Rotation), 크기(Scale), 밀림(Shearing), 반사(Reflection), 이동(Translation)와 같은 2차원 변환인 Affine Transform에 취약하다. 즉, Affine Tranform으로 변환된 영상은 다른 영상으로 인식한다. 

또한 이 뿐만 아니라 Noise삽입, 색상, 밝기 변형 등을 활용하여 Data Augmentation 효과를 얻을 수 있다. 

 

Data Augmentation을 위한 데이터 생성(generator)하는 방법으로 keras의 ImageDataGenerator을 사용할 수 있다. 이 Data Generator는 이미지에 변화를 주면서 컴퓨터의 학습자료로 이용하여 더욱 효과적이고 과적합을 방지하는 방식으로 학습할 수 있도록 한다. 

(https://keraskorea.github.io/posts/2018-10-24-little_data_powerful_model/글에서 알려준 바에 따라)

ImageDataGenerator는 

1. 학습 도중 이미지에 임의 변형 및 정규화를 적용해 주고

2. 변형된 이미지를 배치 단위로 불러올 수 있는 Generator을 생성해 준다. 

  • generator 생성 할 때, flow(data, label)flow_from_directory(directory) 두 가지 함수를 사용하며
  • 이미지를 불러오고 모델을 학습 할 때, fit_generatorevaluate_generator 함수를 사용한다. 

3. genetor의 transformation parameter(이미지에 어떤 변화를 줄 수 있는지)는 매우 많으며, 그 중 대표적으로 많이 사용되는 것들은

  • rotation_range
  • width_shift_range
  • height_shift_range
  • brightness_range
  • zoom_range
  • horizontal_flip
  • vertical_flip
  • preprocessing_function 
  • rescale
    • : transformation은 이미지에 변화를 주어서 학습 데이터를 많게 해서 성능을 높이기 위해 하는 것이기 때문에 train set만 해주고, test set에는 해 줄 필요가 없다. 그러나 주의할 것은 Rescale은 train, test 모두 해 주어야 한다.
train_datagenerator = ImageDataGenerator(
    zoom_range = 0.7,
    rescale = 1. /255.
)

test_datagenerator = ImageDataGenerator(
    rescale = 1. /255.
)

등이 있다. (참고:  www.keras.io/preprocessing/image/ )

 

 

2. 구현

1) flow(data, label) 사용하여 generator생성하는 경우

MNIST 데이터를 사용하여 datagenerator.flow(inputs) 형식으로 Data Augmentation을 진행한다. 

# 0. 필요한 함수 import
import os
from glob import glob
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

#1. 데이터 파일 경로찾기 및 Read, Load Image
data_path = glob('/dataset/mnist_png/training/0/*.png')
path = data_path[0]

gfile = tf.io.read_file(path)
image = tf.io.decode_image(gfile)
image.shape #[28, 28, 1]

#2. Set Data Generator
import tensorflow.keras.preprocessing.imgae import ImageDataGenerator
#datagenerator 생성
datagenerator = ImageDataGenerator(
	rotation_range = 20, 
    width_shift_range = 0.2, 
    height_shift_ragne = 0.2, 
    horizontal_flip = True
)
#생성한 datagenerator을 image에 적용
image = image[tf.newaxis, ...]
image.shape #[1, 28, 28, 1]
image_result = next(iter(datagenerator.flow(image)) #이러면 datagenerator에서 설정해준 것들이 하나씩 적용된다. 
#original image와 transformation된 image 시각화해서 보기
plt.subplot(1, 2, 1)
plt.title('original')
plt.imshow(np.squeeze(image), 'gray')
plt.subplot(1, 2, 2)
plt.title('Transforms Image')
plt.imshow(np.squeeze(image_result), 'gray')
plt.show()

#####################.flow() 함수는 임의 변환된 이미지를 배치 단위로 생성해서 지정한 폴더에 저장할 수 있다.########
##################### 즉, 하나하나 적용해서 각 image_result로 만들고 batch로 묶고 싶다면, 
i = 0
for batch in datagenerator.flow(image, batch_size=1,
                          save_to_dir=`preview`, save_prefix=`label`, save_format=`png`):
    i += 1
    if i > 20:
        break  # 이미지 20장을 생성하고 마칩니다

2) flow_from_directory(directory) 사용하여 generator생성하는 경우

MNIST 데이터를 사용하여 datagenerator.flow_from_directory(directory) 형식으로 Data Augmentation을 진행한다. 

  • datagenerator.flow(inputs)는 이미지를 load 후 => datagenerator을 적용
  • datagenerator.flow_from_directory(directory)는 => 해당 경로에 있는 image load와 datagenerator 함께 가능
# 0. 필요한 함수 import
import os
from glob import glob
import tensorflow as tf
import numpy as np

#1. 데이터 파일 경로찾기
train_dir = 'dataset/mnist_png/training'
test_dir ='dataset/mnist_png/testing'

#2. Set Data Generator
import tensorflow.keras.preprocessing.imgae import ImageDataGenerator
#datagenerator 생성
train_datagenerator = ImageDataGenerator(
	rescale = 1./255.,
    width_shift_range = 0.3,
    zoom_range = 0.7,
    horizontal_flip = True
)
test_datagenerator = ImageDataGenerator(
	rescale = 1./255.,
)
#train_datagenerator을 train image에 적용
train_result = train_datagenerator.flow_from_directory(
	train_dir, 
    target_size = input_shape[:2],
    batch_size = batch_size,
     class_mode=`binary`  # binary_crossentropy 손실 함수를 사용하므로 binary 형태로 라벨을 불러와야 합니다.
)
#test_datagenerator을 test image에 적용
test_result = test_datagenerator.flow_from_directory(
	test_dir, 
    target_size = input_shape[:2],
    batch_size = batch_size,
     class_mode=`binary`  # binary_crossentropy 손실 함수를 사용하므로 binary 형태로 라벨을 불러와야 합니다.
)

#3. model 생성 후, 
inputs = layers.Input(input_shape)
net = layers.Conv2D(32, 3, padding = 'SAME')(inputs)
net = layers.Activation('relu')(net)
net = layers.Conv2D(32, 3, padding = 'SAME')(net)
net = layers.Activation('relu')(net)
net = layers.MaxPooling2D(pool_size = 2)(net)
net = layers.Dropout(dropout_rate)(net)

net = layers.Conv2D(64, 3, padding = 'SAME')(net)
net = layers.Activation('relu')(net)
net = layers.Conv2D(64, 3, padding = 'SAME')(net)
net = layers.Activation('relu')(net)
net = layers.MaxPooling2D(pool_size = 2)(net)
net = layers.Dropout(dropout_rate)(net)

net = layers.Flatten()(net)
net = layers.Dense(512)(net)
net = layers.Activation('relu')(net)
net = layers.Dense(num_classes)(net)
net = layers.Activation('softmax')(net)

model = tf.keras.Model(inputs = inputs, outputs = net, name = 'Basic_CNN')

model.compile(optimizer = tf.keras.optimizers.Adam(learning_rate), #Optimization
             loss = 'categorical_crossentropy', #Loss function
             metrics = ['accuracy']) #Metrics/Accuracy
#4. Training
model.fit_generator(
    train_generator, 
    steps_per_epoch = len(train_generator), 
    epochs = num_epochs,
    validation_data =validation_generator, 
    validation_steps = len(validation_generator))#steps_per_epoch : 한 epoch에 몇 개의 묶음의 이미지(batch)가 epoch에 돌아갈지
)
Test도 마찬가지


 

reference

fastcampus - 인공지능과 딥러닝 강의

https://www.kdnuggets.com/2018/05/data-augmentation-deep-learning-limited-data.html

https://keraskorea.github.io/posts/2018-10-24-little_data_powerful_model/

www.keras.io/preprocessing/image/